HHH-5697 - Support for multi-tenancy
This commit is contained in:
parent
98877a3b28
commit
3ff0288da5
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
/**
|
||||
* Describes the methods for multi-tenancy understood by Hibernate.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public enum MultiTenancyStrategy {
|
||||
/**
|
||||
* Multi-tenancy implemented by use of discriminator columns.
|
||||
*/
|
||||
DISCRIMINATOR,
|
||||
/**
|
||||
* Multi-tenancy implemented as separate schemas.
|
||||
*/
|
||||
SCHEMA,
|
||||
/**
|
||||
* Multi-tenancy implemented as separate databases.
|
||||
*/
|
||||
DATABASE,
|
||||
/**
|
||||
* No multi-tenancy
|
||||
*/
|
||||
NONE;
|
||||
|
||||
public static MultiTenancyStrategy determineMultiTenancyStrategy(Map properties) {
|
||||
final Object strategy = properties.get( Environment.MULTI_TENANT );
|
||||
if ( strategy == null ) {
|
||||
return MultiTenancyStrategy.NONE;
|
||||
}
|
||||
|
||||
if ( MultiTenancyStrategy.class.isInstance( strategy ) ) {
|
||||
return (MultiTenancyStrategy) strategy;
|
||||
}
|
||||
|
||||
final String strategyName = strategy.toString();
|
||||
if ( MultiTenancyStrategy.DISCRIMINATOR.name().equals( strategyName ) ) {
|
||||
return MultiTenancyStrategy.DISCRIMINATOR;
|
||||
}
|
||||
else if ( MultiTenancyStrategy.SCHEMA.name().equals( strategyName ) ) {
|
||||
return MultiTenancyStrategy.SCHEMA;
|
||||
}
|
||||
else if ( MultiTenancyStrategy.DATABASE.name().equals( strategyName ) ) {
|
||||
return MultiTenancyStrategy.DATABASE;
|
||||
}
|
||||
else if ( MultiTenancyStrategy.NONE.name().equals( strategyName ) ) {
|
||||
return MultiTenancyStrategy.NONE;
|
||||
}
|
||||
else {
|
||||
// todo log?
|
||||
return MultiTenancyStrategy.NONE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,6 +31,24 @@ import java.io.Serializable;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SharedSessionContract extends Serializable {
|
||||
/**
|
||||
* Obtain the tenant identifier associated with this session.
|
||||
*
|
||||
* @return The tenant identifier associated with this session, or {@code null}
|
||||
*/
|
||||
public String getTenantIdentifier();
|
||||
|
||||
/**
|
||||
* Should be set only once for the session. Would rather this be supplied to opening the session, as
|
||||
* being discussed for HHH-2860
|
||||
*
|
||||
* @param identifier The tenant identifier.
|
||||
*
|
||||
* @deprecated HHH-2860
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTenantIdentifier(String identifier);
|
||||
|
||||
/**
|
||||
* Begin a unit of work and return the associated {@link Transaction} object. If a new underlying transaction is
|
||||
* required, begin the transaction. Otherwise continue the new work in the context of the existing underlying
|
||||
|
|
|
@ -551,6 +551,11 @@ public final class Environment {
|
|||
*/
|
||||
public static final String NON_CONTEXTUAL_LOB_CREATION = "hibernate.jdbc.lob.non_contextual_creation";
|
||||
|
||||
/**
|
||||
* Strategy for multi-tenancy.
|
||||
* @see org.hibernate.MultiTenancyStrategy
|
||||
*/
|
||||
public static final String MULTI_TENANT = "hibernate.multiTenancy";
|
||||
|
||||
private static final BytecodeProvider BYTECODE_PROVIDER_INSTANCE;
|
||||
private static final boolean ENABLE_BINARY_STREAMS;
|
||||
|
|
|
@ -26,6 +26,7 @@ package org.hibernate.cfg;
|
|||
import java.util.Map;
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.cache.QueryCacheFactory;
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.hql.QueryTranslatorFactory;
|
||||
|
@ -81,6 +82,7 @@ public final class Settings {
|
|||
// private ComponentTuplizerFactory componentTuplizerFactory; todo : HHH-3517 and HHH-1907
|
||||
// private BytecodeProvider bytecodeProvider;
|
||||
private String importFiles;
|
||||
private MultiTenancyStrategy multiTenancyStrategy;
|
||||
|
||||
private JtaPlatform jtaPlatform;
|
||||
|
||||
|
@ -438,4 +440,12 @@ public final class Settings {
|
|||
void setJtaPlatform(JtaPlatform jtaPlatform) {
|
||||
this.jtaPlatform = jtaPlatform;
|
||||
}
|
||||
|
||||
public MultiTenancyStrategy getMultiTenancyStrategy() {
|
||||
return multiTenancyStrategy;
|
||||
}
|
||||
|
||||
void setMultiTenancyStrategy(MultiTenancyStrategy multiTenancyStrategy) {
|
||||
this.multiTenancyStrategy = multiTenancyStrategy;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.hibernate.ConnectionReleaseMode;
|
|||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.HibernateLogger;
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.cache.QueryCacheFactory;
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.impl.NoCachingRegionFactory;
|
||||
|
@ -241,6 +242,9 @@ public class SettingsFactory implements Serializable {
|
|||
LOG.checkNullability(enabledDisabled(checkNullability));
|
||||
settings.setCheckNullability(checkNullability);
|
||||
|
||||
MultiTenancyStrategy multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( properties );
|
||||
LOG.debug( "multi-tenancy strategy : " + multiTenancyStrategy );
|
||||
settings.setMultiTenancyStrategy( multiTenancyStrategy );
|
||||
|
||||
// String provider = properties.getProperty( Environment.BYTECODE_PROVIDER );
|
||||
// log.info( "Bytecode provider name : " + provider );
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.hibernate.ConnectionReleaseMode;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.SessionFactoryObserver;
|
||||
|
@ -52,6 +53,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.TypeResolver;
|
||||
|
@ -255,7 +257,7 @@ public interface SessionFactoryImplementor extends Mapping, SessionFactory {
|
|||
*/
|
||||
public FetchProfile getFetchProfile(String name);
|
||||
|
||||
public ServiceRegistry getServiceRegistry();
|
||||
public ServiceRegistryImplementor getServiceRegistry();
|
||||
|
||||
public void addObserver(SessionFactoryObserver observer);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Middleware LLC.
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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
|
||||
|
@ -20,7 +20,6 @@
|
|||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
package org.hibernate.engine;
|
||||
|
||||
|
@ -39,6 +38,7 @@ import org.hibernate.ScrollMode;
|
|||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.collection.PersistentCollection;
|
||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
|
||||
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.event.EventListeners;
|
||||
|
@ -47,16 +47,21 @@ import org.hibernate.loader.custom.CustomQuery;
|
|||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
|
||||
/**
|
||||
* Defines the internal contract between the <tt>Session</tt> and other parts of
|
||||
* Hibernate such as implementors of <tt>Type</tt> or <tt>EntityPersister</tt>.
|
||||
* Defines the internal contract between {@link org.hibernate.Session} / {@link org.hibernate.StatelessSession} and
|
||||
* other parts of Hibernate such as {@link Type}, {@link EntityPersister} and
|
||||
* {@link org.hibernate.persister.collection.CollectionPersister} implementors
|
||||
*
|
||||
* @see org.hibernate.Session the interface to the application
|
||||
* @see org.hibernate.impl.SessionImpl the actual implementation
|
||||
* @author Gavin King
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SessionImplementor extends Serializable, LobCreationContext {
|
||||
/**
|
||||
* Provides access to JDBC connections
|
||||
*
|
||||
* @return The contract for accessing JDBC connections.
|
||||
*/
|
||||
public JdbcConnectionAccess getJdbcConnectionAccess();
|
||||
|
||||
/**
|
||||
* Retrieves the interceptor currently in use by this event source.
|
||||
|
|
|
@ -71,7 +71,8 @@ public class JdbcCoordinatorImpl implements JdbcCoordinator {
|
|||
this.logicalConnection = new LogicalConnectionImpl(
|
||||
userSuppliedConnection,
|
||||
transactionCoordinator.getTransactionContext().getConnectionReleaseMode(),
|
||||
transactionCoordinator.getTransactionContext().getTransactionEnvironment().getJdbcServices()
|
||||
transactionCoordinator.getTransactionContext().getTransactionEnvironment().getJdbcServices(),
|
||||
transactionCoordinator.getTransactionContext().getJdbcConnectionAccess()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,21 +22,28 @@
|
|||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.internal;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.HibernateLogger;
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.LobCreationContext;
|
||||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.spi.ExtractedDatabaseMetaData;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.ResultSetWrapper;
|
||||
import org.hibernate.engine.jdbc.spi.SchemaNameResolver;
|
||||
|
@ -45,41 +52,39 @@ import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
|
|||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
|
||||
import org.hibernate.service.jdbc.dialect.spi.DialectFactory;
|
||||
import org.hibernate.service.spi.Configurable;
|
||||
import org.hibernate.service.spi.InjectService;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.hibernate.service.spi.ServiceRegistryAwareService;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
/**
|
||||
* Standard implementation of the {@link JdbcServices} contract
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcServicesImpl implements JdbcServices, Configurable {
|
||||
|
||||
public class JdbcServicesImpl implements JdbcServices, ServiceRegistryAwareService, Configurable {
|
||||
private static final HibernateLogger LOG = Logger.getMessageLogger(HibernateLogger.class, JdbcServicesImpl.class.getName());
|
||||
|
||||
private ConnectionProvider connectionProvider;
|
||||
|
||||
@InjectService
|
||||
public void setConnectionProvider(ConnectionProvider connectionProvider) {
|
||||
this.connectionProvider = connectionProvider;
|
||||
}
|
||||
|
||||
private DialectFactory dialectFactory;
|
||||
|
||||
@InjectService
|
||||
public void setDialectFactory(DialectFactory dialectFactory) {
|
||||
this.dialectFactory = dialectFactory;
|
||||
}
|
||||
private ServiceRegistryImplementor serviceRegistry;
|
||||
|
||||
private Dialect dialect;
|
||||
private ConnectionProvider connectionProvider;
|
||||
private SqlStatementLogger sqlStatementLogger;
|
||||
private SqlExceptionHelper sqlExceptionHelper;
|
||||
private ExtractedDatabaseMetaData extractedMetaDataSupport;
|
||||
private LobCreatorBuilder lobCreatorBuilder;
|
||||
|
||||
@Override
|
||||
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(Map configValues) {
|
||||
final JdbcConnectionAccess jdbcConnectionAccess = buildJdbcConnectionAccess( configValues );
|
||||
final DialectFactory dialectFactory = serviceRegistry.getService( DialectFactory.class );
|
||||
|
||||
Dialect dialect = null;
|
||||
LobCreatorBuilder lobCreatorBuilder = null;
|
||||
|
||||
|
@ -105,9 +110,9 @@ public class JdbcServicesImpl implements JdbcServices, Configurable {
|
|||
boolean useJdbcMetadata = ConfigurationHelper.getBoolean( "hibernate.temp.use_jdbc_metadata_defaults", configValues, true );
|
||||
if ( useJdbcMetadata ) {
|
||||
try {
|
||||
Connection conn = connectionProvider.getConnection();
|
||||
Connection connection = jdbcConnectionAccess.obtainConnection();
|
||||
try {
|
||||
DatabaseMetaData meta = conn.getMetaData();
|
||||
DatabaseMetaData meta = connection.getMetaData();
|
||||
LOG.database(meta.getDatabaseProductName(),
|
||||
meta.getDatabaseProductVersion(),
|
||||
meta.getDatabaseMajorVersion(),
|
||||
|
@ -128,25 +133,25 @@ public class JdbcServicesImpl implements JdbcServices, Configurable {
|
|||
lobLocatorUpdateCopy = meta.locatorsUpdateCopy();
|
||||
typeInfoSet.addAll( TypeInfoExtracter.extractTypeInfo( meta ) );
|
||||
|
||||
dialect = dialectFactory.buildDialect( configValues, conn );
|
||||
dialect = dialectFactory.buildDialect( configValues, connection );
|
||||
|
||||
catalogName = conn.getCatalog();
|
||||
catalogName = connection.getCatalog();
|
||||
SchemaNameResolver schemaNameResolver = determineExplicitSchemaNameResolver( configValues );
|
||||
if ( schemaNameResolver == null ) {
|
||||
// todo : add dialect method
|
||||
// schemaNameResolver = dialect.getSchemaNameResolver();
|
||||
}
|
||||
if ( schemaNameResolver != null ) {
|
||||
schemaName = schemaNameResolver.resolveSchemaName( conn );
|
||||
schemaName = schemaNameResolver.resolveSchemaName( connection );
|
||||
}
|
||||
lobCreatorBuilder = new LobCreatorBuilder( configValues, conn );
|
||||
lobCreatorBuilder = new LobCreatorBuilder( configValues, connection );
|
||||
}
|
||||
catch ( SQLException sqle ) {
|
||||
LOG.unableToObtainConnectionMetadata(sqle.getMessage());
|
||||
}
|
||||
finally {
|
||||
if ( conn != null ) {
|
||||
connectionProvider.closeConnection( conn );
|
||||
if ( connection != null ) {
|
||||
jdbcConnectionAccess.releaseConnection( connection );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -190,6 +195,57 @@ public class JdbcServicesImpl implements JdbcServices, Configurable {
|
|||
);
|
||||
}
|
||||
|
||||
private JdbcConnectionAccess buildJdbcConnectionAccess(Map configValues) {
|
||||
final MultiTenancyStrategy multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configValues );
|
||||
|
||||
if ( MultiTenancyStrategy.NONE == multiTenancyStrategy ) {
|
||||
connectionProvider = serviceRegistry.getService( ConnectionProvider.class );
|
||||
return new ConnectionProviderJdbcConnectionAccess( connectionProvider );
|
||||
}
|
||||
else {
|
||||
connectionProvider = null;
|
||||
final MultiTenantConnectionProvider multiTenantConnectionProvider = serviceRegistry.getService( MultiTenantConnectionProvider.class );
|
||||
return new MultiTenantConnectionProviderJdbcConnectionAccess( multiTenantConnectionProvider );
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess {
|
||||
private final ConnectionProvider connectionProvider;
|
||||
|
||||
public ConnectionProviderJdbcConnectionAccess(ConnectionProvider connectionProvider) {
|
||||
this.connectionProvider = connectionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection obtainConnection() throws SQLException {
|
||||
return connectionProvider.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection connection) throws SQLException {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MultiTenantConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess {
|
||||
private final MultiTenantConnectionProvider connectionProvider;
|
||||
|
||||
public MultiTenantConnectionProviderJdbcConnectionAccess(MultiTenantConnectionProvider connectionProvider) {
|
||||
this.connectionProvider = connectionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection obtainConnection() throws SQLException {
|
||||
return connectionProvider.getAnyConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection connection) throws SQLException {
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// todo : add to Environment
|
||||
public static final String SCHEMA_NAME_RESOLVER = "hibernate.schema_name_resolver";
|
||||
|
||||
|
@ -220,9 +276,7 @@ public class JdbcServicesImpl implements JdbcServices, Configurable {
|
|||
|
||||
private Set<String> parseKeywords(String extraKeywordsString) {
|
||||
Set<String> keywordSet = new HashSet<String>();
|
||||
for ( String keyword : extraKeywordsString.split( "," ) ) {
|
||||
keywordSet.add( keyword );
|
||||
}
|
||||
keywordSet.addAll( Arrays.asList( extraKeywordsString.split( "," ) ) );
|
||||
return keywordSet;
|
||||
}
|
||||
|
||||
|
@ -278,81 +332,93 @@ public class JdbcServicesImpl implements JdbcServices, Configurable {
|
|||
this.typeInfoSet = typeInfoSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsScrollableResults() {
|
||||
return supportsScrollableResults;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsGetGeneratedKeys() {
|
||||
return supportsGetGeneratedKeys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsBatchUpdates() {
|
||||
return supportsBatchUpdates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsDataDefinitionInTransaction() {
|
||||
return supportsDataDefinitionInTransaction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesDataDefinitionCauseTransactionCommit() {
|
||||
return doesDataDefinitionCauseTransactionCommit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getExtraKeywords() {
|
||||
return extraKeywords;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SQLStateType getSqlStateType() {
|
||||
return sqlStateType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesLobLocatorUpdateCopy() {
|
||||
return lobLocatorUpdateCopy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionSchemaName() {
|
||||
return connectionSchemaName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionCatalogName() {
|
||||
return connectionCatalogName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashSet<TypeInfo> getTypeInfoSet() {
|
||||
return typeInfoSet;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionProvider getConnectionProvider() {
|
||||
return connectionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlStatementLogger getSqlStatementLogger() {
|
||||
return sqlStatementLogger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlExceptionHelper getSqlExceptionHelper() {
|
||||
return sqlExceptionHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialect getDialect() {
|
||||
return dialect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtractedDatabaseMetaData getExtractedMetaDataSupport() {
|
||||
return extractedMetaDataSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public LobCreator getLobCreator(LobCreationContext lobCreationContext) {
|
||||
return lobCreatorBuilder.buildLobCreator( lobCreationContext );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public ResultSetWrapper getResultSetWrapper() {
|
||||
return ResultSetWrapperImpl.INSTANCE;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.hibernate.HibernateLogger;
|
|||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
|
||||
import org.hibernate.engine.jdbc.spi.ConnectionObserver;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcResourceRegistry;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.jdbc.spi.LogicalConnectionImplementor;
|
||||
|
@ -61,6 +62,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
|||
|
||||
private final transient ConnectionReleaseMode connectionReleaseMode;
|
||||
private final transient JdbcServices jdbcServices;
|
||||
private final transient JdbcConnectionAccess jdbcConnectionAccess;
|
||||
private final transient JdbcResourceRegistry jdbcResourceRegistry;
|
||||
private final transient List<ConnectionObserver> observers;
|
||||
|
||||
|
@ -73,10 +75,12 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
|||
public LogicalConnectionImpl(
|
||||
Connection userSuppliedConnection,
|
||||
ConnectionReleaseMode connectionReleaseMode,
|
||||
JdbcServices jdbcServices) {
|
||||
JdbcServices jdbcServices,
|
||||
JdbcConnectionAccess jdbcConnectionAccess) {
|
||||
this(
|
||||
connectionReleaseMode,
|
||||
jdbcServices,
|
||||
jdbcConnectionAccess,
|
||||
(userSuppliedConnection != null),
|
||||
false,
|
||||
new ArrayList<ConnectionObserver>()
|
||||
|
@ -87,6 +91,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
|||
private LogicalConnectionImpl(
|
||||
ConnectionReleaseMode connectionReleaseMode,
|
||||
JdbcServices jdbcServices,
|
||||
JdbcConnectionAccess jdbcConnectionAccess,
|
||||
boolean isUserSuppliedConnection,
|
||||
boolean isClosed,
|
||||
List<ConnectionObserver> observers) {
|
||||
|
@ -94,6 +99,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
|||
jdbcServices, isUserSuppliedConnection, connectionReleaseMode
|
||||
);
|
||||
this.jdbcServices = jdbcServices;
|
||||
this.jdbcConnectionAccess = jdbcConnectionAccess;
|
||||
this.jdbcResourceRegistry = new JdbcResourceRegistryImpl( getJdbcServices().getSqlExceptionHelper() );
|
||||
this.observers = observers;
|
||||
|
||||
|
@ -286,7 +292,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
|||
private void obtainConnection() throws JDBCException {
|
||||
LOG.debugf("Obtaining JDBC connection");
|
||||
try {
|
||||
physicalConnection = getJdbcServices().getConnectionProvider().getConnection();
|
||||
physicalConnection = jdbcConnectionAccess.obtainConnection();
|
||||
for ( ConnectionObserver observer : observers ) {
|
||||
observer.physicalConnectionObtained( physicalConnection );
|
||||
}
|
||||
|
@ -304,13 +310,19 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
|||
*/
|
||||
private void releaseConnection() throws JDBCException {
|
||||
LOG.debugf("Releasing JDBC connection");
|
||||
if ( physicalConnection == null ) return;
|
||||
try {
|
||||
if (!physicalConnection.isClosed()) getJdbcServices().getSqlExceptionHelper().logAndClearWarnings(physicalConnection);
|
||||
if (!isUserSuppliedConnection) getJdbcServices().getConnectionProvider().closeConnection(physicalConnection);
|
||||
if ( physicalConnection == null ) {
|
||||
return;
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
throw getJdbcServices().getSqlExceptionHelper().convert( sqle, "Could not close connection" );
|
||||
try {
|
||||
if ( ! physicalConnection.isClosed() ) {
|
||||
getJdbcServices().getSqlExceptionHelper().logAndClearWarnings( physicalConnection );
|
||||
}
|
||||
if ( ! isUserSuppliedConnection ) {
|
||||
jdbcConnectionAccess.releaseConnection( physicalConnection );
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw getJdbcServices().getSqlExceptionHelper().convert( e, "Could not close connection" );
|
||||
}
|
||||
finally {
|
||||
physicalConnection = null;
|
||||
|
@ -424,6 +436,7 @@ public class LogicalConnectionImpl implements LogicalConnectionImplementor {
|
|||
return new LogicalConnectionImpl(
|
||||
transactionContext.getConnectionReleaseMode(),
|
||||
transactionContext.getTransactionEnvironment().getJdbcServices(),
|
||||
transactionContext.getJdbcConnectionAccess(),
|
||||
isUserSuppliedConnection,
|
||||
isClosed,
|
||||
observers
|
||||
|
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.spi;
|
||||
import java.io.Serializable;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
|
||||
/**
|
||||
* Encapsulates JDBC Connection management SPI.
|
||||
* <p/>
|
||||
* The lifecycle is intended to span a logical series of interactions with the
|
||||
* database. Internally, this means the the lifecycle of the Session.
|
||||
*
|
||||
* @author Gail Badner
|
||||
*/
|
||||
public interface ConnectionManager extends Serializable {
|
||||
|
||||
/**
|
||||
* Retrieves the connection currently managed by this ConnectionManager.
|
||||
* <p/>
|
||||
* Note, that we may need to obtain a connection to return here if a
|
||||
* connection has either not yet been obtained (non-UserSuppliedConnectionProvider)
|
||||
* or has previously been aggressively released (if supported in this environment).
|
||||
*
|
||||
* @return The current Connection.
|
||||
*
|
||||
* @throws HibernateException Indicates a connection is currently not
|
||||
* available (we are currently manually disconnected).
|
||||
*/
|
||||
Connection getConnection();
|
||||
|
||||
// TODO: should this be removd from the SPI?
|
||||
boolean hasBorrowedConnection();
|
||||
|
||||
// TODO: should this be removd from the SPI?
|
||||
void releaseBorrowedConnection();
|
||||
|
||||
/**
|
||||
* Is this ConnectionManager instance "logically" connected. Meaning
|
||||
* do we either have a cached connection available or do we have the
|
||||
* ability to obtain a connection on demand.
|
||||
*
|
||||
* @return True if logically connected; false otherwise.
|
||||
*/
|
||||
boolean isCurrentlyConnected();
|
||||
|
||||
/**
|
||||
* To be called after execution of each JDBC statement. Used to
|
||||
* conditionally release the JDBC connection aggressively if
|
||||
* the configured release mode indicates.
|
||||
*/
|
||||
void afterStatement();
|
||||
|
||||
/**
|
||||
* Sets the transaction timeout.
|
||||
* @param seconds - number of seconds until the the transaction times out.
|
||||
*/
|
||||
void setTransactionTimeout(int seconds);
|
||||
|
||||
/**
|
||||
* To be called after Session completion. Used to release the JDBC
|
||||
* connection.
|
||||
*
|
||||
* @return The connection mantained here at time of close. Null if
|
||||
* there was no connection cached internally.
|
||||
*/
|
||||
Connection close();
|
||||
|
||||
/**
|
||||
* Manually disconnect the underlying JDBC Connection. The assumption here
|
||||
* is that the manager will be reconnected at a later point in time.
|
||||
*
|
||||
* @return The connection mantained here at time of disconnect. Null if
|
||||
* there was no connection cached internally.
|
||||
*/
|
||||
Connection manualDisconnect();
|
||||
|
||||
/**
|
||||
* Manually reconnect the underlying JDBC Connection. Should be called at
|
||||
* some point after manualDisconnect().
|
||||
* <p/>
|
||||
* This form is used for ConnectionProvider-supplied connections.
|
||||
*/
|
||||
void manualReconnect();
|
||||
|
||||
/**
|
||||
* Manually reconnect the underlying JDBC Connection. Should be called at
|
||||
* some point after manualDisconnect().
|
||||
* <p/>
|
||||
* This form is used for user-supplied connections.
|
||||
*/
|
||||
void manualReconnect(Connection suppliedConnection);
|
||||
|
||||
/**
|
||||
* Callback to let us know that a flush is beginning. We use this fact
|
||||
* to temporarily circumvent aggressive connection releasing until after
|
||||
* the flush cycle is complete {@link #flushEnding()}
|
||||
*/
|
||||
void flushBeginning();
|
||||
|
||||
/**
|
||||
* Callback to let us know that a flush is ending. We use this fact to
|
||||
* stop circumventing aggressive releasing connections.
|
||||
*/
|
||||
void flushEnding();
|
||||
|
||||
/**
|
||||
* Get a non-batchable prepared statement to use for inserting / deleting / updating,
|
||||
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, int)}).
|
||||
* <p/>
|
||||
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
|
||||
* released when the session is closed or disconnected.
|
||||
*/
|
||||
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys);
|
||||
|
||||
/**
|
||||
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
|
||||
* using JDBC3 getGeneratedKeys ({@link java.sql.Connection#prepareStatement(String, String[])}).
|
||||
* <p/>
|
||||
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
|
||||
* released when the session is closed or disconnected.
|
||||
*/
|
||||
public PreparedStatement prepareStatement(String sql, String[] columnNames);
|
||||
|
||||
/**
|
||||
* Get a non-batchable prepared statement to use for selecting. Does not
|
||||
* result in execution of the current batch.
|
||||
* <p/>
|
||||
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
|
||||
* it will be released when the session is closed or disconnected.
|
||||
*/
|
||||
public PreparedStatement prepareSelectStatement(String sql);
|
||||
|
||||
/**
|
||||
* Get a non-batchable prepared statement to use for inserting / deleting / updating.
|
||||
* <p/>
|
||||
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
|
||||
* released when the session is closed or disconnected.
|
||||
*/
|
||||
public PreparedStatement prepareStatement(String sql, boolean isCallable);
|
||||
|
||||
/**
|
||||
* Get a non-batchable callable statement to use for inserting / deleting / updating.
|
||||
* <p/>
|
||||
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
|
||||
* released when the session is closed or disconnected.
|
||||
*/
|
||||
public CallableStatement prepareCallableStatement(String sql);
|
||||
|
||||
/**
|
||||
* Get a batchable prepared statement to use for inserting / deleting / updating
|
||||
* (might be called many times before a single call to <tt>executeBatch()</tt>).
|
||||
* After setting parameters, call <tt>addToBatch</tt> - do not execute the
|
||||
* statement explicitly.
|
||||
* @see org.hibernate.engine.jdbc.batch.spi.Batch#addToBatch
|
||||
* <p/>
|
||||
* If not explicitly closed via {@link java.sql.PreparedStatement#close()}, it will be
|
||||
* released when the session is closed or disconnected.
|
||||
*/
|
||||
public PreparedStatement prepareBatchStatement(Object key, String sql, boolean isCallable);
|
||||
|
||||
/**
|
||||
* Get a prepared statement for use in loading / querying. Does not
|
||||
* result in execution of the current batch.
|
||||
* <p/>
|
||||
* If not explicitly closed via {@link java.sql.PreparedStatement#close()},
|
||||
* it will be released when the session is closed or disconnected.
|
||||
*/
|
||||
public PreparedStatement prepareQueryStatement(
|
||||
String sql,
|
||||
boolean isScrollable,
|
||||
ScrollMode scrollMode,
|
||||
boolean isCallable);
|
||||
|
||||
/**
|
||||
* Cancel the current query statement
|
||||
*/
|
||||
public void cancelLastQuery();
|
||||
|
||||
public void abortBatch();
|
||||
|
||||
public void addToBatch(Object batchKey, String sql, Expectation expectation);
|
||||
|
||||
public void executeBatch();
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.spi;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Provides centralized access to JDBC connections. Centralized to hide the complexity of accounting for contextual
|
||||
* (multi-tenant) versus non-contextual access.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface JdbcConnectionAccess extends Serializable {
|
||||
public Connection obtainConnection() throws SQLException;
|
||||
public void releaseConnection(Connection connection) throws SQLException;
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.engine.transaction.spi;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
@ -110,4 +111,6 @@ public interface TransactionContext extends Serializable {
|
|||
public void beforeTransactionCompletion(TransactionImplementor hibernateTransaction);
|
||||
|
||||
public void afterTransactionCompletion(TransactionImplementor hibernateTransaction, boolean successful);
|
||||
|
||||
public JdbcConnectionAccess getJdbcConnectionAccess();
|
||||
}
|
||||
|
|
|
@ -30,11 +30,13 @@ import java.sql.SQLException;
|
|||
import java.util.List;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.SQLQuery;
|
||||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.SessionException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.NamedQueryDefinition;
|
||||
import org.hibernate.engine.NamedSQLQueryDefinition;
|
||||
import org.hibernate.engine.QueryParameters;
|
||||
|
@ -48,6 +50,8 @@ import org.hibernate.engine.transaction.spi.TransactionContext;
|
|||
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
|
||||
import org.hibernate.jdbc.WorkExecutor;
|
||||
import org.hibernate.jdbc.WorkExecutorVisitable;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
|
||||
|
||||
/**
|
||||
* Functionality common to stateless and stateful sessions
|
||||
|
@ -57,6 +61,7 @@ import org.hibernate.jdbc.WorkExecutorVisitable;
|
|||
public abstract class AbstractSessionImpl implements Serializable, SharedSessionContract, SessionImplementor, TransactionContext {
|
||||
|
||||
protected transient SessionFactoryImpl factory;
|
||||
private String tenantIdentifier;
|
||||
private boolean closed = false;
|
||||
|
||||
protected AbstractSessionImpl(SessionFactoryImpl factory) {
|
||||
|
@ -203,4 +208,77 @@ public abstract class AbstractSessionImpl implements Serializable, SharedSession
|
|||
return scrollCustomQuery( getNativeSQLQueryPlan( spec ).getCustomQuery(), queryParameters );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTenantIdentifier() {
|
||||
return tenantIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTenantIdentifier(String identifier) {
|
||||
if ( MultiTenancyStrategy.NONE == factory.getSettings().getMultiTenancyStrategy() ) {
|
||||
throw new HibernateException( "SessionFactory was not configured for multi-tenancy" );
|
||||
}
|
||||
this.tenantIdentifier = identifier;
|
||||
}
|
||||
|
||||
private transient JdbcConnectionAccess jdbcConnectionAccess;
|
||||
|
||||
@Override
|
||||
public JdbcConnectionAccess getJdbcConnectionAccess() {
|
||||
if ( jdbcConnectionAccess == null ) {
|
||||
if ( MultiTenancyStrategy.NONE == factory.getSettings().getMultiTenancyStrategy() ) {
|
||||
jdbcConnectionAccess = new NonContextualJdbcConnectionAccess(
|
||||
factory.getServiceRegistry().getService( ConnectionProvider.class )
|
||||
);
|
||||
}
|
||||
else {
|
||||
jdbcConnectionAccess = new ContextualJdbcConnectionAccess(
|
||||
factory.getServiceRegistry().getService( MultiTenantConnectionProvider.class )
|
||||
);
|
||||
}
|
||||
}
|
||||
return jdbcConnectionAccess;
|
||||
}
|
||||
|
||||
private static class NonContextualJdbcConnectionAccess implements JdbcConnectionAccess, Serializable {
|
||||
private final ConnectionProvider connectionProvider;
|
||||
|
||||
private NonContextualJdbcConnectionAccess(ConnectionProvider connectionProvider) {
|
||||
this.connectionProvider = connectionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection obtainConnection() throws SQLException {
|
||||
return connectionProvider.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection connection) throws SQLException {
|
||||
connectionProvider.closeConnection( connection );
|
||||
}
|
||||
}
|
||||
|
||||
private class ContextualJdbcConnectionAccess implements JdbcConnectionAccess, Serializable {
|
||||
private final MultiTenantConnectionProvider connectionProvider;
|
||||
|
||||
private ContextualJdbcConnectionAccess(MultiTenantConnectionProvider connectionProvider) {
|
||||
this.connectionProvider = connectionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection obtainConnection() throws SQLException {
|
||||
if ( tenantIdentifier == null ) {
|
||||
throw new HibernateException( "Tenant identifier required!" );
|
||||
}
|
||||
return connectionProvider.getConnection( tenantIdentifier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection connection) throws SQLException {
|
||||
if ( tenantIdentifier == null ) {
|
||||
throw new HibernateException( "Tenant identifier required!" );
|
||||
}
|
||||
connectionProvider.releaseConnection( tenantIdentifier, connection );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.HibernateLogger;
|
||||
import org.hibernate.Interceptor;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.ObjectNotFoundException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.Session;
|
||||
|
@ -212,6 +213,7 @@ public final class SessionFactoryImpl
|
|||
this.properties = new Properties();
|
||||
this.properties.putAll( cfg.getProperties() );
|
||||
this.interceptor = cfg.getInterceptor();
|
||||
|
||||
this.serviceRegistry = serviceRegistry.getService( SessionFactoryServiceRegistryFactory.class ).buildServiceRegistry(
|
||||
this,
|
||||
cfg
|
||||
|
@ -1260,10 +1262,11 @@ public final class SessionFactoryImpl
|
|||
}
|
||||
|
||||
@Override
|
||||
public ServiceRegistry getServiceRegistry() {
|
||||
public ServiceRegistryImplementor getServiceRegistry() {
|
||||
return serviceRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityNotFoundDelegate getEntityNotFoundDelegate() {
|
||||
return entityNotFoundDelegate;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.hibernate.persister.spi.PersisterClassResolver;
|
|||
import org.hibernate.persister.spi.PersisterFactory;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.spi.ServiceRegistryAwareService;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
@ -75,10 +76,10 @@ public final class PersisterFactoryImpl implements PersisterFactory, ServiceRegi
|
|||
SessionFactoryImplementor.class
|
||||
};
|
||||
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private ServiceRegistryImplementor serviceRegistry;
|
||||
|
||||
@Override
|
||||
public void injectServices(ServiceRegistry serviceRegistry) {
|
||||
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.persister.internal.PersisterFactoryInitiator;
|
|||
import org.hibernate.service.classloading.internal.ClassLoaderServiceInitiator;
|
||||
import org.hibernate.service.internal.SessionFactoryServiceRegistryFactoryInitiator;
|
||||
import org.hibernate.service.jdbc.connections.internal.ConnectionProviderInitiator;
|
||||
import org.hibernate.service.jdbc.connections.internal.MultiTenantConnectionProviderInitiator;
|
||||
import org.hibernate.service.jdbc.dialect.internal.DialectFactoryInitiator;
|
||||
import org.hibernate.service.jdbc.dialect.internal.DialectResolverInitiator;
|
||||
import org.hibernate.service.jmx.internal.JmxServiceInitiator;
|
||||
|
@ -58,6 +59,7 @@ public class StandardServiceInitiators {
|
|||
serviceInitiators.add( PersisterFactoryInitiator.INSTANCE );
|
||||
|
||||
serviceInitiators.add( ConnectionProviderInitiator.INSTANCE );
|
||||
serviceInitiators.add( MultiTenantConnectionProviderInitiator.INSTANCE );
|
||||
serviceInitiators.add( DialectResolverInitiator.INSTANCE );
|
||||
serviceInitiators.add( DialectFactoryInitiator.INSTANCE );
|
||||
serviceInitiators.add( BatchBuilderInitiator.INSTANCE );
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
|
@ -125,12 +125,12 @@ public class BasicServiceRegistryImpl extends AbstractServiceRegistryImpl implem
|
|||
protected <T extends Service> void configureService(T service) {
|
||||
applyInjections( service );
|
||||
|
||||
if ( Configurable.class.isInstance( service ) ) {
|
||||
( (Configurable) service ).configure( configurationValues );
|
||||
}
|
||||
|
||||
if ( ServiceRegistryAwareService.class.isInstance( service ) ) {
|
||||
( (ServiceRegistryAwareService) service ).injectServices( this );
|
||||
}
|
||||
|
||||
if ( Configurable.class.isInstance( service ) ) {
|
||||
( (Configurable) service ).configure( configurationValues );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.jboss.logging.Logger;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.HibernateLogger;
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.internal.util.beans.BeanInfoHelper;
|
||||
import org.hibernate.service.classloading.spi.ClassLoaderService;
|
||||
|
@ -100,6 +101,10 @@ public class ConnectionProviderInitiator implements BasicServiceInitiator<Connec
|
|||
|
||||
@Override
|
||||
public ConnectionProvider initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
|
||||
if ( MultiTenancyStrategy.determineMultiTenancyStrategy( configurationValues ) != MultiTenancyStrategy.NONE ) {
|
||||
// nothing to do, but given the separate hierarchies have to handle this here.
|
||||
}
|
||||
|
||||
final ClassLoaderService classLoaderService = registry.getService( ClassLoaderService.class );
|
||||
|
||||
ConnectionProvider connectionProvider = null;
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.service.jdbc.connections.internal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
|
||||
import org.hibernate.service.spi.BasicServiceInitiator;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MultiTenantConnectionProviderInitiator implements BasicServiceInitiator<MultiTenantConnectionProvider> {
|
||||
public static final MultiTenantConnectionProviderInitiator INSTANCE = new MultiTenantConnectionProviderInitiator();
|
||||
|
||||
@Override
|
||||
public Class<MultiTenantConnectionProvider> getServiceInitiated() {
|
||||
return MultiTenantConnectionProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiTenantConnectionProvider initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
|
||||
if ( MultiTenancyStrategy.determineMultiTenancyStrategy( configurationValues ) == MultiTenancyStrategy.NONE ) {
|
||||
// nothing to do, but given the separate hierarchies have to handle this here.
|
||||
}
|
||||
|
||||
// for now...
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.service.jdbc.connections.spi;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.service.UnknownUnwrapTypeException;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractMultiTenantConnectionProvider implements MultiTenantConnectionProvider {
|
||||
protected abstract ConnectionProvider getAnyConnectionProvider();
|
||||
protected abstract ConnectionProvider selectConnectionProvider(String tenantIdentifier);
|
||||
|
||||
@Override
|
||||
public Connection getAnyConnection() throws SQLException {
|
||||
return getAnyConnectionProvider().getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseAnyConnection(Connection connection) throws SQLException {
|
||||
getAnyConnectionProvider().closeConnection( connection );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(String tenantIdentifier) throws SQLException {
|
||||
return selectConnectionProvider( tenantIdentifier ).getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
|
||||
selectConnectionProvider( tenantIdentifier ).getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAggressiveRelease() {
|
||||
return getAnyConnectionProvider().supportsAggressiveRelease();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnwrappableAs(Class unwrapType) {
|
||||
return ConnectionProvider.class.equals( unwrapType ) ||
|
||||
MultiTenantConnectionProvider.class.equals( unwrapType ) ||
|
||||
AbstractMultiTenantConnectionProvider.class.isAssignableFrom( unwrapType );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( {"unchecked"})
|
||||
public <T> T unwrap(Class<T> unwrapType) {
|
||||
if ( isUnwrappableAs( unwrapType ) ) {
|
||||
return (T) this;
|
||||
}
|
||||
else {
|
||||
throw new UnknownUnwrapTypeException( unwrapType );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.service.jdbc.connections.spi;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.service.Service;
|
||||
import org.hibernate.service.spi.Wrapped;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface MultiTenantConnectionProvider extends Service, Wrapped {
|
||||
/**
|
||||
* Allows access to the database metadata of the underlying database(s) in situations where we do not have a
|
||||
* tenant id (like startup processing, for example).
|
||||
*
|
||||
* @return The database metadata.
|
||||
*
|
||||
* @throws SQLException Indicates a problem opening a connection
|
||||
*/
|
||||
public Connection getAnyConnection() throws SQLException;
|
||||
|
||||
/**
|
||||
* Release a connection obtained from {@link #getAnyConnection}
|
||||
*
|
||||
* @param connection The JDBC connection to release
|
||||
*
|
||||
* @throws SQLException Indicates a problem closing the connection
|
||||
*/
|
||||
public void releaseAnyConnection(Connection connection) throws SQLException;
|
||||
|
||||
/**
|
||||
* Obtains a connection for Hibernate use according to the underlying strategy of this provider.
|
||||
*
|
||||
* @param tenantIdentifier The identifier of the tenant for which to get a connection
|
||||
*
|
||||
* @return The obtained JDBC connection
|
||||
*
|
||||
* @throws SQLException Indicates a problem opening a connection
|
||||
* @throws org.hibernate.HibernateException Indicates a problem otherwise obtaining a connection.
|
||||
*/
|
||||
public Connection getConnection(String tenantIdentifier) throws SQLException;
|
||||
|
||||
/**
|
||||
* Release a connection from Hibernate use.
|
||||
*
|
||||
* @param connection The JDBC connection to release
|
||||
* @param tenantIdentifier The identifier of the tenant.
|
||||
*
|
||||
* @throws SQLException Indicates a problem closing the connection
|
||||
* @throws org.hibernate.HibernateException Indicates a problem otherwise releasing a connection.
|
||||
*/
|
||||
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException;
|
||||
|
||||
/**
|
||||
* Does this connection provider support aggressive release of JDBC
|
||||
* connections and re-acquisition of those connections (if need be) later?
|
||||
* <p/>
|
||||
* This is used in conjunction with {@link org.hibernate.cfg.Environment#RELEASE_CONNECTIONS}
|
||||
* to aggressively release JDBC connections. However, the configured ConnectionProvider
|
||||
* must support re-acquisition of the same underlying connection for that semantic to work.
|
||||
* <p/>
|
||||
* Typically, this is only true in managed environments where a container
|
||||
* tracks connections by transaction or thread.
|
||||
*
|
||||
* Note that JTA semantic depends on the fact that the underlying connection provider does
|
||||
* support aggressive release.
|
||||
*
|
||||
* @return {@code true} if aggressive releasing is supported; {@code false} otherwise.
|
||||
*/
|
||||
public boolean supportsAggressiveRelease();
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.hibernate.service.jta.platform.spi.JtaPlatform;
|
|||
import org.hibernate.service.spi.Configurable;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.spi.ServiceRegistryAwareService;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
import javax.transaction.Synchronization;
|
||||
import javax.transaction.SystemException;
|
||||
|
@ -44,10 +45,10 @@ public abstract class AbstractJtaPlatform
|
|||
implements JtaPlatform, Configurable, ServiceRegistryAwareService, TransactionManagerAccess {
|
||||
private boolean cacheTransactionManager;
|
||||
private boolean cacheUserTransaction;
|
||||
private ServiceRegistry serviceRegistry;
|
||||
private ServiceRegistryImplementor serviceRegistry;
|
||||
|
||||
@Override
|
||||
public void injectServices(ServiceRegistry serviceRegistry) {
|
||||
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@
|
|||
*/
|
||||
package org.hibernate.service.spi;
|
||||
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* Allows services to be injected with the {@link org.hibernate.service.ServiceRegistry} during configuration phase.
|
||||
*
|
||||
|
@ -36,5 +34,5 @@ public interface ServiceRegistryAwareService {
|
|||
*
|
||||
* @param serviceRegistry The registry
|
||||
*/
|
||||
public void injectServices(ServiceRegistry serviceRegistry);
|
||||
public void injectServices(ServiceRegistryImplementor serviceRegistry);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import java.sql.SQLException;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
interface ConnectionHelper {
|
||||
public interface ConnectionHelper {
|
||||
/**
|
||||
* Prepare the helper for use.
|
||||
*
|
||||
|
|
|
@ -157,6 +157,17 @@ public class SchemaExport {
|
|||
);
|
||||
}
|
||||
|
||||
public SchemaExport(
|
||||
ConnectionHelper connectionHelper,
|
||||
String[] dropSql,
|
||||
String[] createSql) {
|
||||
this.connectionHelper = connectionHelper;
|
||||
this.dropSQL = dropSql;
|
||||
this.createSQL = createSql;
|
||||
this.importFiles = "";
|
||||
this.formatter = FormatStyle.DDL.getFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* For generating a export script file, this is the file which will be written.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.common;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcConnectionAccessImpl implements JdbcConnectionAccess {
|
||||
private final ConnectionProvider connectionProvider;
|
||||
|
||||
public JdbcConnectionAccessImpl(TransactionEnvironment transactionEnvironment) {
|
||||
this( transactionEnvironment.getSessionFactory().getServiceRegistry() );
|
||||
}
|
||||
|
||||
public JdbcConnectionAccessImpl(ConnectionProvider connectionProvider) {
|
||||
this.connectionProvider = connectionProvider;
|
||||
}
|
||||
|
||||
public JdbcConnectionAccessImpl(ServiceRegistry serviceRegistry) {
|
||||
this( serviceRegistry.getService( ConnectionProvider.class ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection obtainConnection() throws SQLException {
|
||||
return connectionProvider.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection connection) throws SQLException {
|
||||
connectionProvider.closeConnection( connection );
|
||||
}
|
||||
}
|
|
@ -24,18 +24,30 @@
|
|||
package org.hibernate.test.common;
|
||||
|
||||
import org.hibernate.ConnectionReleaseMode;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
|
||||
import org.hibernate.engine.transaction.spi.TransactionContext;
|
||||
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
|
||||
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TransactionContextImpl implements TransactionContext {
|
||||
private final TransactionEnvironment transactionEnvironment;
|
||||
private final JdbcConnectionAccess jdbcConnectionAccess;
|
||||
|
||||
public TransactionContextImpl(TransactionEnvironment transactionEnvironment, JdbcConnectionAccess jdbcConnectionAccess) {
|
||||
this.transactionEnvironment = transactionEnvironment;
|
||||
this.jdbcConnectionAccess = jdbcConnectionAccess;
|
||||
}
|
||||
|
||||
public TransactionContextImpl(TransactionEnvironment transactionEnvironment, ServiceRegistry serviceRegistry) {
|
||||
this( transactionEnvironment, new JdbcConnectionAccessImpl( serviceRegistry ) );
|
||||
}
|
||||
|
||||
public TransactionContextImpl(TransactionEnvironment transactionEnvironment) {
|
||||
this.transactionEnvironment = transactionEnvironment;
|
||||
this( transactionEnvironment, new JdbcConnectionAccessImpl( transactionEnvironment.getJdbcServices().getConnectionProvider() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,6 +60,11 @@ public class TransactionContextImpl implements TransactionContext {
|
|||
return transactionEnvironment.getTransactionFactory().getDefaultReleaseMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcConnectionAccess getJdbcConnectionAccess() {
|
||||
return jdbcConnectionAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldAutoJoinTransaction() {
|
||||
return true;
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.junit.Test;
|
|||
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
import org.hibernate.test.common.BasicTestingJdbcServiceImpl;
|
||||
import org.hibernate.test.common.JdbcConnectionAccessImpl;
|
||||
import org.hibernate.test.common.JournalingConnectionObserver;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -112,7 +113,12 @@ public class AggressiveReleaseTest extends BaseUnitTestCase {
|
|||
|
||||
@Test
|
||||
public void testBasicRelease() {
|
||||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl( null, ConnectionReleaseMode.AFTER_STATEMENT, services );
|
||||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl(
|
||||
null,
|
||||
ConnectionReleaseMode.AFTER_STATEMENT,
|
||||
services ,
|
||||
new JdbcConnectionAccessImpl( services.getConnectionProvider() )
|
||||
);
|
||||
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
|
||||
JournalingConnectionObserver observer = new JournalingConnectionObserver();
|
||||
logicalConnection.addObserver( observer );
|
||||
|
@ -142,7 +148,12 @@ public class AggressiveReleaseTest extends BaseUnitTestCase {
|
|||
|
||||
@Test
|
||||
public void testReleaseCircumventedByHeldResources() {
|
||||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl( null, ConnectionReleaseMode.AFTER_STATEMENT, services );
|
||||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl(
|
||||
null,
|
||||
ConnectionReleaseMode.AFTER_STATEMENT,
|
||||
services,
|
||||
new JdbcConnectionAccessImpl( services.getConnectionProvider() )
|
||||
);
|
||||
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
|
||||
JournalingConnectionObserver observer = new JournalingConnectionObserver();
|
||||
logicalConnection.addObserver( observer );
|
||||
|
@ -196,7 +207,12 @@ public class AggressiveReleaseTest extends BaseUnitTestCase {
|
|||
|
||||
@Test
|
||||
public void testReleaseCircumventedManually() {
|
||||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl( null, ConnectionReleaseMode.AFTER_STATEMENT, services );
|
||||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl(
|
||||
null,
|
||||
ConnectionReleaseMode.AFTER_STATEMENT,
|
||||
services,
|
||||
new JdbcConnectionAccessImpl( services.getConnectionProvider() )
|
||||
);
|
||||
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
|
||||
JournalingConnectionObserver observer = new JournalingConnectionObserver();
|
||||
logicalConnection.addObserver( observer );
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.hibernate.JDBCException;
|
|||
import org.hibernate.engine.jdbc.internal.LogicalConnectionImpl;
|
||||
import org.hibernate.engine.jdbc.internal.proxy.ProxyBuilder;
|
||||
import org.hibernate.test.common.BasicTestingJdbcServiceImpl;
|
||||
import org.hibernate.test.common.JdbcConnectionAccessImpl;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -64,7 +65,8 @@ public class BasicConnectionProxyTest extends BaseUnitTestCase {
|
|||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl(
|
||||
null,
|
||||
ConnectionReleaseMode.AFTER_TRANSACTION,
|
||||
services
|
||||
services,
|
||||
new JdbcConnectionAccessImpl( services.getConnectionProvider() )
|
||||
);
|
||||
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
|
||||
try {
|
||||
|
@ -92,7 +94,8 @@ public class BasicConnectionProxyTest extends BaseUnitTestCase {
|
|||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl(
|
||||
null,
|
||||
ConnectionReleaseMode.AFTER_TRANSACTION,
|
||||
services
|
||||
services,
|
||||
new JdbcConnectionAccessImpl( services.getConnectionProvider() )
|
||||
);
|
||||
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
|
||||
try {
|
||||
|
@ -114,7 +117,8 @@ public class BasicConnectionProxyTest extends BaseUnitTestCase {
|
|||
LogicalConnectionImpl logicalConnection = new LogicalConnectionImpl(
|
||||
null,
|
||||
ConnectionReleaseMode.AFTER_TRANSACTION,
|
||||
services
|
||||
services,
|
||||
new JdbcConnectionAccessImpl( services.getConnectionProvider() )
|
||||
);
|
||||
Connection proxiedConnection = ProxyBuilder.buildConnection( logicalConnection );
|
||||
|
||||
|
|
|
@ -91,7 +91,9 @@ public class BatchingTest extends BaseUnitTestCase implements BatchKey {
|
|||
|
||||
@Test
|
||||
public void testNonBatchingUsage() throws Exception {
|
||||
final TransactionContext transactionContext = new TransactionContextImpl( new TransactionEnvironmentImpl( serviceRegistry ) );
|
||||
final TransactionContext transactionContext = new TransactionContextImpl(
|
||||
new TransactionEnvironmentImpl( serviceRegistry )
|
||||
);
|
||||
|
||||
TransactionCoordinatorImpl transactionCoordinator = new TransactionCoordinatorImpl( null, transactionContext );
|
||||
JournalingTransactionObserver observer = new JournalingTransactionObserver();
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.multitenancy.schema;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Entity
|
||||
public class Customer {
|
||||
private Long id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
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,206 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2011, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* 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, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY 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
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.multitenancy.schema;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MultiTenancyStrategy;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.internal.BasicServiceRegistryImpl;
|
||||
import org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
|
||||
import org.hibernate.service.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.tool.hbm2ddl.ConnectionHelper;
|
||||
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.env.ConnectionProviderBuilder;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.testing.junit4.BaseUnitTestCase;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SchemaBasedMultiTenancyTest extends BaseUnitTestCase {
|
||||
private DriverManagerConnectionProviderImpl acmeProvider;
|
||||
private DriverManagerConnectionProviderImpl jbossProvider;
|
||||
|
||||
private ServiceRegistryImplementor serviceRegistry;
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
acmeProvider = ConnectionProviderBuilder.buildConnectionProvider( "acme" );
|
||||
jbossProvider = ConnectionProviderBuilder.buildConnectionProvider( "jboss" );
|
||||
AbstractMultiTenantConnectionProvider multiTenantConnectionProvider = new AbstractMultiTenantConnectionProvider() {
|
||||
@Override
|
||||
protected ConnectionProvider getAnyConnectionProvider() {
|
||||
return acmeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
|
||||
if ( "acme".equals( tenantIdentifier ) ) {
|
||||
return acmeProvider;
|
||||
}
|
||||
else if ( "jboss".equals( tenantIdentifier ) ) {
|
||||
return jbossProvider;
|
||||
}
|
||||
throw new HibernateException( "Unknown tenant identifier" );
|
||||
}
|
||||
};
|
||||
|
||||
Configuration cfg = new Configuration();
|
||||
cfg.getProperties().put( Environment.MULTI_TENANT, MultiTenancyStrategy.DATABASE );
|
||||
cfg.addAnnotatedClass( Customer.class );
|
||||
|
||||
cfg.buildMappings();
|
||||
|
||||
// do the acme export
|
||||
new SchemaExport(
|
||||
new ConnectionHelper() {
|
||||
private Connection connection;
|
||||
@Override
|
||||
public void prepare(boolean needsAutoCommit) throws SQLException {
|
||||
connection = acmeProvider.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() throws SQLException {
|
||||
acmeProvider.closeConnection( connection );
|
||||
}
|
||||
},
|
||||
cfg.generateDropSchemaScript( ConnectionProviderBuilder.getCorrespondingDialect() ),
|
||||
cfg.generateSchemaCreationScript( ConnectionProviderBuilder.getCorrespondingDialect() )
|
||||
).execute( // so stupid...
|
||||
false, // do not script the export (write it to file)
|
||||
true, // do run it against the database
|
||||
false, // do not *just* perform the drop
|
||||
false // do not *just* perform the create
|
||||
);
|
||||
|
||||
// do the jboss export
|
||||
new SchemaExport(
|
||||
new ConnectionHelper() {
|
||||
private Connection connection;
|
||||
@Override
|
||||
public void prepare(boolean needsAutoCommit) throws SQLException {
|
||||
connection = jbossProvider.getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() throws SQLException {
|
||||
jbossProvider.closeConnection( connection );
|
||||
}
|
||||
},
|
||||
cfg.generateDropSchemaScript( ConnectionProviderBuilder.getCorrespondingDialect() ),
|
||||
cfg.generateSchemaCreationScript( ConnectionProviderBuilder.getCorrespondingDialect() )
|
||||
).execute( // so stupid...
|
||||
false, // do not script the export (write it to file)
|
||||
true, // do run it against the database
|
||||
false, // do not *just* perform the drop
|
||||
false // do not *just* perform the create
|
||||
);
|
||||
|
||||
serviceRegistry = new BasicServiceRegistryImpl( cfg.getProperties() );
|
||||
serviceRegistry.registerService( MultiTenantConnectionProvider.class, multiTenantConnectionProvider );
|
||||
|
||||
sessionFactory = cfg.buildSessionFactory( serviceRegistry );
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if ( sessionFactory != null ) {
|
||||
sessionFactory.close();
|
||||
}
|
||||
if ( serviceRegistry != null ) {
|
||||
serviceRegistry.destroy();
|
||||
}
|
||||
if ( jbossProvider != null ) {
|
||||
jbossProvider.stop();
|
||||
}
|
||||
if ( acmeProvider != null ) {
|
||||
acmeProvider.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private Session openSession() {
|
||||
return sessionFactory.openSession();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicExpectedBehavior() {
|
||||
Session session = openSession();
|
||||
session.setTenantIdentifier( "jboss" );
|
||||
session.beginTransaction();
|
||||
Customer steve = new Customer( "steve" );
|
||||
session.save( steve );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
||||
session = openSession();
|
||||
try {
|
||||
session.setTenantIdentifier( "acme" );
|
||||
session.beginTransaction();
|
||||
Customer check = (Customer) session.get( Customer.class, steve.getId() );
|
||||
Assert.assertNull( "tenancy not properly isolated", check );
|
||||
}
|
||||
finally {
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
session = openSession();
|
||||
session.setTenantIdentifier( "jboss" );
|
||||
session.beginTransaction();
|
||||
session.delete( steve );
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -29,7 +29,6 @@ import org.hibernate.cfg.Environment;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.service.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
|
||||
import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
||||
|
||||
/**
|
||||
* Defines the JDBC connection information (currently H2) used by Hibernate for unit (not functional!) tests
|
||||
|
@ -38,24 +37,36 @@ import org.hibernate.service.jdbc.connections.spi.ConnectionProvider;
|
|||
*/
|
||||
public class ConnectionProviderBuilder {
|
||||
public static final String DRIVER = "org.h2.Driver";
|
||||
public static final String URL = "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE";
|
||||
public static final String URL = "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;MVCC=TRUE";
|
||||
public static final String USER = "sa";
|
||||
public static final String PASS = "";
|
||||
|
||||
public static Properties getConnectionProviderProperties() {
|
||||
public static Properties getConnectionProviderProperties(String dbName) {
|
||||
Properties props = new Properties( null );
|
||||
props.put( Environment.DRIVER, DRIVER );
|
||||
props.put( Environment.URL, URL );
|
||||
props.put( Environment.URL, String.format( URL, dbName ) );
|
||||
props.put( Environment.USER, USER );
|
||||
props.put( Environment.PASS, PASS );
|
||||
return props;
|
||||
}
|
||||
|
||||
public static ConnectionProvider buildConnectionProvider() {
|
||||
public static Properties getConnectionProviderProperties() {
|
||||
return getConnectionProviderProperties( "db1" );
|
||||
}
|
||||
|
||||
public static DriverManagerConnectionProviderImpl buildConnectionProvider() {
|
||||
return buildConnectionProvider( false );
|
||||
}
|
||||
|
||||
public static ConnectionProvider buildConnectionProvider(final boolean allowAggressiveRelease) {
|
||||
final Properties props = getConnectionProviderProperties();
|
||||
public static DriverManagerConnectionProviderImpl buildConnectionProvider(String dbName) {
|
||||
return buildConnectionProvider( getConnectionProviderProperties( dbName ), false );
|
||||
}
|
||||
|
||||
public static DriverManagerConnectionProviderImpl buildConnectionProvider(final boolean allowAggressiveRelease) {
|
||||
return buildConnectionProvider( getConnectionProviderProperties( "db1" ), allowAggressiveRelease );
|
||||
}
|
||||
|
||||
private static DriverManagerConnectionProviderImpl buildConnectionProvider(Properties props, final boolean allowAggressiveRelease) {
|
||||
DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl() {
|
||||
public boolean supportsAggressiveRelease() {
|
||||
return allowAggressiveRelease;
|
||||
|
|
Loading…
Reference in New Issue