Author: epbernard
Date: 2010-07-30 06:07:26 -0400 (Fri, 30 Jul 2010)
New Revision: 20082
Added:
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/DataSourceByNameProvider.java
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/H2dataSourceProvider.java
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/JBossTSStandaloneTransactionManagerLookup.java
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/PersistenceUnitInfoBuilder.java
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/ReadOnlyPersistenceUnitInfo.java
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/XADataSourceWrapper.java
Log:
HSEARCH-562 Add JTA test with JBoss TS: Add infrastructural code for JBossTS
In particular:
- PersistenceUnitInfo builder to use Hibernate's EMF creation "in
container"
- XADatasourceWrapper that does not use JNDI but use a static lookup mechanism
- create datasource holder for H2
- create JBossTSStandaloneTransactionManagerLookup (to be contributed to Hibernate
Core?)
Added:
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/DataSourceByNameProvider.java
===================================================================
---
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/DataSourceByNameProvider.java
(rev 0)
+++
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/DataSourceByNameProvider.java 2010-07-30
10:07:26 UTC (rev 20082)
@@ -0,0 +1,28 @@
+package org.hibernate.search.test.integration.jbossjta.infra;
+
+import java.sql.SQLException;
+import javax.sql.XADataSource;
+
+import com.arjuna.ats.internal.jdbc.DynamicClass;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class DataSourceByNameProvider implements DynamicClass {
+ private final XADataSource datasource;
+ private final String name;
+
+ public DataSourceByNameProvider(String name, XADataSource datasource) {
+ this.name = name;
+ this.datasource = datasource;
+ }
+
+ public XADataSource getDataSource(String dbName) throws SQLException {
+ if ( name.equals( dbName ) ) {
+ return datasource;
+ }
+ else {
+ throw new IllegalArgumentException( "Datasource not found: " + dbName );
+ }
+ }
+}
\ No newline at end of file
Added:
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/H2dataSourceProvider.java
===================================================================
---
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/H2dataSourceProvider.java
(rev 0)
+++
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/H2dataSourceProvider.java 2010-07-30
10:07:26 UTC (rev 20082)
@@ -0,0 +1,33 @@
+package org.hibernate.search.test.integration.jbossjta.infra;
+
+import java.sql.SQLException;
+import javax.sql.XADataSource;
+
+import com.arjuna.ats.internal.jdbc.DynamicClass;
+import org.h2.jdbcx.JdbcDataSource;
+
+/**
+ * Bind a H2 DataSource to the name "h2"
+ *
+ * @author Emmanuel Bernard
+ */
+public class H2dataSourceProvider implements DynamicClass {
+ private static String DATASOURCE_NAME = "h2";
+ private static DynamicClass dynamicClass;
+
+ static {
+ final JdbcDataSource dataSource = new JdbcDataSource();
+ dataSource.setURL( "jdbc:h2:file:h2db" );
+ dataSource.setUser( "sa" );
+ dataSource.setPassword( "" );
+ dynamicClass = new DataSourceByNameProvider( DATASOURCE_NAME, dataSource );
+ }
+
+ public String getDataSourceName() {
+ return DATASOURCE_NAME;
+ }
+
+ public XADataSource getDataSource(String dbName) throws SQLException {
+ return dynamicClass.getDataSource( dbName );
+ }
+}
Added:
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/JBossTSStandaloneTransactionManagerLookup.java
===================================================================
---
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/JBossTSStandaloneTransactionManagerLookup.java
(rev 0)
+++
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/JBossTSStandaloneTransactionManagerLookup.java 2010-07-30
10:07:26 UTC (rev 20082)
@@ -0,0 +1,29 @@
+package org.hibernate.search.test.integration.jbossjta.infra;
+
+import java.util.Properties;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple;
+import org.jboss.tm.TransactionManagerFactory;
+
+import org.hibernate.HibernateException;
+import org.hibernate.transaction.TransactionManagerLookup;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class JBossTSStandaloneTransactionManagerLookup implements
TransactionManagerLookup {
+ public TransactionManager getTransactionManager(Properties props) throws
HibernateException {
+ //TODO use reflection
+ return new TransactionManagerImple();
+ }
+
+ public String getUserTransactionName() {
+ return null;
+ }
+
+ public Object getTransactionIdentifier(Transaction transaction) {
+ return transaction;
+ }
+}
Added:
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/PersistenceUnitInfoBuilder.java
===================================================================
---
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/PersistenceUnitInfoBuilder.java
(rev 0)
+++
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/PersistenceUnitInfoBuilder.java 2010-07-30
10:07:26 UTC (rev 20082)
@@ -0,0 +1,109 @@
+package org.hibernate.search.test.integration.jbossjta.infra;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import javax.persistence.SharedCacheMode;
+import javax.persistence.ValidationMode;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+
+public class PersistenceUnitInfoBuilder {
+ private String persistenceUnitName;
+ private String persistenceProviderClassName;
+ private PersistenceUnitTransactionType transactionType;
+ private DataSource jtaDataSource;
+ private URL persistenceUnitRootUrl;
+ private List<String> managedClassNames;
+ private boolean excludeUnlistedClasses;
+ private SharedCacheMode sharedCacheMode;
+ private ValidationMode validationMode;
+ private Properties properties;
+ private String persistenceXMLSchemaVersion;
+ private ClassLoader classLoader;
+
+ public PersistenceUnitInfoBuilder() {
+ classLoader = Thread.currentThread().getContextClassLoader();
+ persistenceUnitRootUrl = classLoader.getResource( "persistence.xml" );
+ managedClassNames = new ArrayList<String>();
+ properties = new Properties( );
+ }
+
+ public PersistenceUnitInfoBuilder setPersistenceUnitName(String persistenceUnitName) {
+ this.persistenceUnitName = persistenceUnitName;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setPersistenceProviderClassName(String
persistenceProviderClassName) {
+ this.persistenceProviderClassName = persistenceProviderClassName;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setTransactionType(PersistenceUnitTransactionType
transactionType) {
+ this.transactionType = transactionType;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setJtaDataSource(DataSource jtaDataSource) {
+ this.jtaDataSource = jtaDataSource;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setPersistenceUnitRootUrl(URL persistenceUnitRootUrl)
{
+ this.persistenceUnitRootUrl = persistenceUnitRootUrl;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder addManagedClassNames(String managedClassName) {
+ this.managedClassNames.add( managedClassName );
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setExcludeUnlistedClasses(boolean
excludeUnlistedClasses) {
+ this.excludeUnlistedClasses = excludeUnlistedClasses;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setSharedCacheMode(SharedCacheMode sharedCacheMode) {
+ this.sharedCacheMode = sharedCacheMode;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setValidationMode(ValidationMode validationMode) {
+ this.validationMode = validationMode;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder addProperty(String key, String value) {
+ this.properties.setProperty( key, value );
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setPersistenceXMLSchemaVersion(String
persistenceXMLSchemaVersion) {
+ this.persistenceXMLSchemaVersion = persistenceXMLSchemaVersion;
+ return this;
+ }
+
+ public PersistenceUnitInfoBuilder setClassLoader(ClassLoader classLoader) {
+ this.classLoader = classLoader;
+ return this;
+ }
+
+ public ReadOnlyPersistenceUnitInfo create() {
+ return new ReadOnlyPersistenceUnitInfo(
+ persistenceUnitName,
+ persistenceProviderClassName,
+ transactionType,
+ jtaDataSource,
+ persistenceUnitRootUrl,
+ managedClassNames,
+ excludeUnlistedClasses,
+ sharedCacheMode,
+ validationMode,
+ properties,
+ persistenceXMLSchemaVersion,
+ classLoader
+ );
+ }
+}
\ No newline at end of file
Added:
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/ReadOnlyPersistenceUnitInfo.java
===================================================================
---
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/ReadOnlyPersistenceUnitInfo.java
(rev 0)
+++
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/ReadOnlyPersistenceUnitInfo.java 2010-07-30
10:07:26 UTC (rev 20082)
@@ -0,0 +1,112 @@
+package org.hibernate.search.test.integration.jbossjta.infra;
+
+import java.net.URL;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import javax.persistence.SharedCacheMode;
+import javax.persistence.ValidationMode;
+import javax.persistence.spi.ClassTransformer;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+import javax.sql.DataSource;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ReadOnlyPersistenceUnitInfo implements PersistenceUnitInfo {
+ private final String persistenceUnitName;
+ private final String persistenceProviderClassName;
+ private final PersistenceUnitTransactionType transactionType;
+ private final DataSource jtaDataSource;
+ private final URL persistenceUnitRootUrl;
+ private final List<String> managedClassNames;
+ private final boolean excludeUnlistedClasses;
+ private final SharedCacheMode sharedCacheMode;
+ private final ValidationMode validationMode;
+ private final Properties properties;
+ private final String persistenceXMLSchemaVersion;
+ private final ClassLoader classLoader;
+
+ public ReadOnlyPersistenceUnitInfo(String persistenceUnitName, String
persistenceProviderClassName, PersistenceUnitTransactionType transactionType, DataSource
jtaDataSource, URL persistenceUnitRootUrl, List<String> managedClassNames, boolean
excludeUnlistedClasses, SharedCacheMode sharedCacheMode, ValidationMode validationMode,
Properties properties, String persistenceXMLSchemaVersion, ClassLoader classLoader) {
+ this.persistenceUnitName = persistenceUnitName;
+ this.persistenceProviderClassName = persistenceProviderClassName;
+ this.transactionType = transactionType;
+ this.jtaDataSource = jtaDataSource;
+ this.persistenceUnitRootUrl = persistenceUnitRootUrl;
+ this.managedClassNames = managedClassNames;
+ this.excludeUnlistedClasses = excludeUnlistedClasses;
+ this.sharedCacheMode = sharedCacheMode;
+ this.validationMode = validationMode;
+ this.properties = properties;
+ this.persistenceXMLSchemaVersion = persistenceXMLSchemaVersion;
+ this.classLoader = classLoader;
+ }
+
+ public String getPersistenceUnitName() {
+ return persistenceUnitName;
+ }
+
+ public String getPersistenceProviderClassName() {
+ return persistenceProviderClassName;
+ }
+
+ public PersistenceUnitTransactionType getTransactionType() {
+ return transactionType;
+ }
+
+ public DataSource getJtaDataSource() {
+ return jtaDataSource;
+ }
+
+ public DataSource getNonJtaDataSource() {
+ return null;
+ }
+
+ public List<String> getMappingFileNames() {
+ return Collections.EMPTY_LIST;
+ }
+
+ public List<URL> getJarFileUrls() {
+ return Collections.EMPTY_LIST;
+ }
+
+ public URL getPersistenceUnitRootUrl() {
+ return persistenceUnitRootUrl;
+ }
+
+ public List<String> getManagedClassNames() {
+ return managedClassNames;
+ }
+
+ public boolean excludeUnlistedClasses() {
+ return excludeUnlistedClasses;
+ }
+
+ public SharedCacheMode getSharedCacheMode() {
+ return sharedCacheMode;
+ }
+
+ public ValidationMode getValidationMode() {
+ return validationMode;
+ }
+
+ public Properties getProperties() {
+ return properties;
+ }
+
+ public String getPersistenceXMLSchemaVersion() {
+ return persistenceXMLSchemaVersion;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public void addTransformer(ClassTransformer transformer) {
+ }
+
+ public ClassLoader getNewTempClassLoader() {
+ return null;
+ }
+}
Added:
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/XADataSourceWrapper.java
===================================================================
---
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/XADataSourceWrapper.java
(rev 0)
+++
search/trunk/hibernate-search-integrationtest/src/test/java/org/hibernate/search/test/integration/jbossjta/infra/XADataSourceWrapper.java 2010-07-30
10:07:26 UTC (rev 20082)
@@ -0,0 +1,194 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU Lesser General Public License, v. 2.1.
+ * This program is distributed in the hope that it will be useful, but WITHOUT A
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ * You should have received a copy of the GNU Lesser General Public License,
+ * v.2.1 along with this distribution; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * (C) 2008,
+ * @author JBoss Inc.
+ */
+package org.hibernate.search.test.integration.jbossjta.infra;
+
+import javax.sql.XADataSource;
+import javax.sql.XAConnection;
+import javax.sql.DataSource;
+import javax.naming.Context;
+import java.sql.SQLException;
+import java.sql.Connection;
+import java.io.PrintWriter;
+import java.util.Properties;
+
+import com.arjuna.ats.jdbc.TransactionalDriver;
+import com.arjuna.ats.jdbc.common.jdbcPropertyManager;
+//import com.arjuna.common.util.propertyservice.PropertyManager;
+
+
+/**
+ * This class provides a DataSource based approach to
+ * management of transaction aware database connections.
+ * <p/>
+ * It's a XADataSource from which they can obtain a XAResource.
+ * Hence it implements both DataSource and XADataSource.
+ *
+ * @author Jonathan Halliday jonathan.halliday(a)redhat.com
+ * @author Emmanuel Bernard
+ * @since 2008-05
+ */
+public class XADataSourceWrapper implements XADataSource, DataSource {
+ private XADataSource _theXADataSource;
+ private final TransactionalDriver _theTransactionalDriver = new TransactionalDriver();
+ private String _name;
+ private Properties defaultProperties = new Properties();
+
+ /**
+ * Create a wrapper around the provided XADataSource implementation,
+ * which should be registered in tomcat's global JNDI with the specified name.
+ * Note: the registration is not done here, it's someone elses problem.
+ * See TransactionalResourceFactory for example usage.
+ *
+ * @param name should be the fully qualifed JNDI name of the XADataSource, in
+ * tomcat's global JNDI, not a webapp specific JNDI context.
+ * @param theDataSource
+ */
+ public XADataSourceWrapper(String name, XADataSource theDataSource) {
+ _theXADataSource = theDataSource;
+ _name = name;
+ }
+
+ public void setProperty(String key, String value) {
+ defaultProperties.setProperty( key, value );
+ }
+
+ /**
+ * Obtain a direct reference to the wrapped object. This is not
+ * recommended but may be necessary to e.g. call vendor specific methods.
+ *
+ * @return
+ */
+ public XADataSource getUnwrappedXADataSource() {
+ return _theXADataSource;
+ }
+
+ ///////////////////////
+
+ // Implementation of the DataSource API is done by reusing the arjuna
+ // TransactionalDriver. Its already got all the smarts for checking tx
+ // context, enlisting resources etc so we just delegate to it.
+ // All we need is some fudging to make the JNDI name stuff behave.
+
+ /**
+ * Obtain a connection to the database.
+ * Note: Pooling behaviour depends on the vendor's underlying XADataSource
implementation.
+ *
+ * @return
+ *
+ * @throws SQLException
+ */
+ public Connection getConnection() throws SQLException {
+ String url = TransactionalDriver.arjunaDriver + _name;
+ // although we are not setting any properties, the driver will barf if we pass
'null'.
+ Properties properties = new Properties(defaultProperties);
+ return getTransactionalConnection( url, properties );
+ }
+
+ /**
+ * Obtain a connection to the database using the supplied authentication credentials.
+ *
+ * @param username
+ * @param password
+ *
+ * @return
+ *
+ * @throws SQLException
+ */
+ public Connection getConnection(String username, String password) throws SQLException {
+ String url = TransactionalDriver.arjunaDriver + _name;
+ Properties properties = new Properties(defaultProperties);
+ properties.setProperty( TransactionalDriver.userName, username );
+ properties.setProperty( TransactionalDriver.password, password );
+ return getTransactionalConnection( url, properties );
+ }
+
+ /*
+ * This is where most of the tomcat specific weirdness resides. You probably
+ * want to subclass and override this method for reuse in env other than tomcat.
+ */
+
+ protected Connection getTransactionalConnection(String url, Properties properties)
throws SQLException {
+ /*
+ // For ref, the url the TransactionalDriver expects is the arjuna driver's
+ // special prefix followed by a JNDI name.
+ // via ConnectionImple the IndirectRecoverableConnection.createDataSource method
+ // attempts to look it up in JNDI. There are two problems with this:
+
+ // First problem,
+ // it always calls InitialContext(env), never InitalContext().
+ // This we work around by copying into the arjuna config, the system
+ // properties it needs to populate the env:
+
+ // caution: ensure the tx lifecycle listener is configured in tomcat or there
will be a
+ // possible race here, as recovery needs these properties too and may start
first
+
jdbcPropertyManager.propertyManager.setProperty("Context.INITIAL_CONTEXT_FACTORY",
System.getProperty(Context.INITIAL_CONTEXT_FACTORY));
+
jdbcPropertyManager.propertyManager.setProperty("Context.URL_PKG_PREFIXES",
System.getProperty(Context.URL_PKG_PREFIXES));
+ */
+
+ Connection connection;
+ connection = _theTransactionalDriver.connect( url, properties );
+ return connection;
+ }
+
+ ///////////////////////
+
+ // Implementation of XADataSource API is just a straightforward wrap/delegate.
+ // Note that some of these methods also appear in the DataSource API.
+ // We don't really care, it's the underlying implementations problem
+ // to disambiguate them if required.
+
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return iface.isAssignableFrom( XADataSource.class );
+ }
+
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ if ( isWrapperFor( iface ) ) {
+ return ( T ) getUnwrappedXADataSource();
+ }
+ else {
+ throw new SQLException( "Not a wrapper for " + iface.getCanonicalName() );
+ }
+ }
+
+ public XAConnection getXAConnection() throws SQLException {
+ return _theXADataSource.getXAConnection();
+ }
+
+ public XAConnection getXAConnection(String user, String password) throws SQLException {
+ return _theXADataSource.getXAConnection( user, password );
+ }
+
+ public PrintWriter getLogWriter() throws SQLException {
+ return _theXADataSource.getLogWriter();
+ }
+
+ public void setLogWriter(PrintWriter out) throws SQLException {
+ _theXADataSource.setLogWriter( out );
+ }
+
+ public void setLoginTimeout(int seconds) throws SQLException {
+ _theXADataSource.setLoginTimeout( seconds );
+ }
+
+ public int getLoginTimeout() throws SQLException {
+ return _theXADataSource.getLoginTimeout();
+ }
+}