SVN layout migration for core/branches/Branch_3_2
git-svn-id: https://svn.jboss.org/repos/hibernate/core/branches/Branch_3_2@11766 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
c654277e62
commit
dadc8d3b9b
|
@ -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);
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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" );
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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() );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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() + "]" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,441 @@
|
||||||
|
//$Id$
|
||||||
|
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.insertordering.InsertOrderingTest;
|
||||||
|
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.NaturalIdSuite;
|
||||||
|
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.reattachment.ReattachmentSuite;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
||||||
|
* <p/>
|
||||||
|
* @see #suite
|
||||||
|
* @param args n/a
|
||||||
|
*/
|
||||||
|
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( NaturalIdSuite.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() );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,616 @@
|
||||||
|
//$Id$
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package org.hibernate.test.any;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* todo: describe PropertyValue
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface PropertyValue {
|
||||||
|
public String asString();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,26 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
//$Id$
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
// $Id$
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
// $Id$
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
//$Id$
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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>
|
|
@ -0,0 +1,62 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
//$Id$
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,34 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,48 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,119 @@
|
||||||
|
//$Id$
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
//$Id$
|
||||||
|
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 org.hibernate.dialect.Oracle9Dialect;
|
||||||
|
|
||||||
|
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 boolean createSchema() {
|
||||||
|
return getDialect().supportsExistsInSelect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() {
|
||||||
|
return new FunctionalTestClassTestSuite( AuctionTest2.class );
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,217 @@
|
||||||
|
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 = new HashMap();
|
||||||
|
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();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,31 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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>
|
112
test/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java
vendored
Normal file
112
test/org/hibernate/test/cache/treecache/optimistic/OptimisticTreeCacheTest.java
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
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.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 ) sfi().getSettings().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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,53 @@
|
||||||
|
// $Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,54 @@
|
||||||
|
// $Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
// $Id$
|
||||||
|
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 ) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,269 @@
|
||||||
|
//$Id$
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -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>
|
|
@ -0,0 +1,73 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,137 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,145 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,75 @@
|
||||||
|
//$Id$
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue