Hi, I ran into an exception and I think it might be a bug, but I'm not sure. Here's what happened:
EDIT: forgot to mention two things:
- Using Hibernate 4.2.0.CR2;
- Despite the exception, the example works. I just want to get rid of the exception.
I'm trying to implement a multi-tenant example called "Agenda" based on the test case for multi-tenant persistence in Hibernate source. I have a single annotated @Entity class called Contact. I have no XML files (neither mapping nor hibernate.cfg.xml). Here's how I create the session factory:
Code:
Configuration cfg = AgendaConnectionProvider.getConfiguration();
ServiceRegistryBuilder registryBuilder = new ServiceRegistryBuilder();
registryBuilder.applySettings(cfg.getProperties());
registryBuilder.addService(MultiTenantConnectionProvider.class, new AgendaConnectionProvider());
ServiceRegistry registry = registryBuilder.buildServiceRegistry();
return cfg.buildSessionFactory(registry);
Also, the Agenda class declares an array of tenants:
Code:
public static final String[] TENANTS = new String[] { "tenant1", "tenant2" };
And here's the code for AgendaConnectionProvider:
Code:
public class AgendaConnectionProvider extends AbstractMultiTenantConnectionProvider {
private static final String DRIVER = "org.h2.Driver";
private static final String URL = "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;MVCC=TRUE";
private static final String USER = "sa";
private static final String PASS = "";
private static final Dialect DIALECT = new H2Dialect();
private static Configuration configuration;
static {
configuration = new Configuration();
configuration.getProperties().put(Environment.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
configuration.addAnnotatedClass(Contact.class);
configuration.buildMapping();
}
static Configuration getConfiguration() {
return configuration;
}
private Map<String, ConnectionProvider> providers;
public AgendaConnectionProvider() {
createProviders();
}
private void createProviders() {
providers = new HashMap<>();
for (String tenant : Agenda.TENANTS) {
Properties props = new Properties(null);
props.put(Environment.DRIVER, DRIVER);
props.put(Environment.URL, String.format(URL, tenant));
props.put(Environment.USER, USER);
props.put(Environment.PASS, PASS);
final DriverManagerConnectionProviderImpl provider = new DriverManagerConnectionProviderImpl();
provider.configure(props);
providers.put(tenant, provider);
ConnectionHelper connectionHelper = new ConnectionHelper() {
private Connection connection;
@Override
public void prepare(boolean needsAutoCommit) throws SQLException {
connection = provider.getConnection();
}
@Override
public Connection getConnection() throws SQLException {
return connection;
}
@Override
public void release() throws SQLException {
provider.closeConnection(connection);
}
};
String[] dropScript = configuracao.generateDropSchemaScript(DIALECT);
String[] createScript = configuracao.generateSchemaCreationScript(DIALECT);
SchemaExport schemaExport = new SchemaExport(connectionHelper, dropScript, createScript);
schemaExport.execute(false, true, false, false);
}
}
@Override
protected ConnectionProvider getAnyConnectionProvider() {
return providers.values().iterator().next();
}
@Override
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
if (!providers.containsKey(tenantIdentifier))
throw new HibernateException("Unknown tenant: " + tenantIdentifier);
return providers.get(tenantIdentifier);
}
}
When I execute my application, this is what I get when the session factory is created:
Code:
ERROR: HHH000231: Schema export unsuccessful
org.hibernate.tool.hbm2ddl.ImportScriptException: Error during statement execution (file: ''): br
at org.hibernate.tool.hbm2ddl.SchemaExport.importScript(SchemaExport.java:451)
at org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:378)
at org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:322)
at br.com.javamagazine.agenda.aplicacao.AgendaConnectionProvider.createProviders(AgendaConnectionProvider.java:106)
at br.com.javamagazine.agenda.aplicacao.AgendaConnectionProvider.<init>(AgendaConnectionProvider.java:61)
at br.com.javamagazine.agenda.aplicacao.Agenda.createSessionFactory(Agenda.java:52)
at br.com.javamagazine.agenda.aplicacao.Agenda.<init>(Agenda.java:40)
at br.com.javamagazine.agenda.aplicacao.Agenda.getInstance(Agenda.java:88)
at br.com.javamagazine.agenda.Main.main(Main.java:7)
Caused by: org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "BR[*] "; expected "BACKUP, BEGIN, {"; SQL statement:
br [42001-170]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:169)
at org.h2.message.DbException.getSyntaxError(DbException.java:194)
at org.h2.command.Parser.getSyntaxError(Parser.java:490)
at org.h2.command.Parser.parsePrepared(Parser.java:475)
at org.h2.command.Parser.parse(Parser.java:278)
at org.h2.command.Parser.parse(Parser.java:254)
at org.h2.command.Parser.prepareCommand(Parser.java:217)
at org.h2.engine.Session.prepareLocal(Session.java:414)
at org.h2.engine.Session.prepareCommand(Session.java:363)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1116)
at org.h2.jdbc.JdbcStatement.executeUpdateInternal(JdbcStatement.java:121)
at org.h2.jdbc.JdbcStatement.executeUpdate(JdbcStatement.java:110)
at org.hibernate.tool.hbm2ddl.DatabaseExporter.export(DatabaseExporter.java:64)
at org.hibernate.tool.hbm2ddl.SchemaExport.importScript(SchemaExport.java:446)
... 8 more
I debugged to see what was happening inside Hibernate, and I found out that the problem is in the method SchemaExport.execute(Target output, Type type):
Code:
final List<NamedReader> importFileReaders = new ArrayList<NamedReader>();
for ( String currentFile : importFiles.split(",") ) {
try {
final String resourceName = currentFile.trim();
InputStream stream = ConfigHelper.getResourceAsStream( resourceName );
importFileReaders.add( new NamedReader( resourceName, stream ) );
}
Basically, importFiles is an empty string ("") and getResourceAsStream() returns the root of the classpath. So it adds to the importFileReaders list the list of files and folders in the classpath. One of these entries is br, because my package starts with br.com. etc... (I'm from Brazil).
The question is: should Hibernate check if importFiles is empty or should I be doing something else to prevent this from happening?
Thanks,
- Vítor Souza