/*
* Copyright 2008-2011 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.nominanuda.hibernate;
import static com.nominanuda.zen.common.Check.illegalargument;
import static java.util.Arrays.asList;
import java.beans.PropertyVetoException;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import javax.sql.DataSource;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.nominanuda.postgresql.PgDataObjectJsonType;
import com.nominanuda.postgresql.PgMapListJsonType;
public class HibernateConfiguration {
private String username;
private String password;
private String connectionUrl;
private Configuration cfg;
private SessionFactory sessionFactory;
private Boolean showSql = Boolean.TRUE;
private ComboPooledDataSource ds = null;
private List<String> resources = new LinkedList<String>();
private String currentSessionContext = "managed";//thread jta
//val an be of type X OR Iterable<X>
//where X is of type SaveOrUpdateEventListener or Class<SaveOrUpdateEventListener>
private boolean dynamic = true;
private boolean c3p0 = false;
public void setC3p0(boolean c3p0) {
this.c3p0 = c3p0;
}
public enum DBType {
MYSQL, HSQLDB, POSTGRESQL, UNKNOWN
}
public HibernateConfiguration() {
// serviceRegistry = new ServiceRegistryBuilder().addService(EventListenerRegistry.class, new EventListenerRegistryImpl()).buildServiceRegistry();
// metadataSources = new MetadataSources(serviceRegistry);
}
public Configuration getConfiguration() {
if(cfg == null) {
cfg = makeConfiguration();
}
return cfg;
}
public SessionFactory getSessionFactory() {
if(sessionFactory == null) {
Configuration cfg = getConfiguration();
sessionFactory = cfg.buildSessionFactory();//serviceRegistry
}
return sessionFactory;
}
private Configuration makeConfiguration() {
//SessionFactory sessionFactory = metadataSources.buildMetadata().buildSessionFactory();
final Configuration cfg = new Configuration();
DBType dbType = inferDbType();
//Configuration cfg = new Configuration();
if(dynamic ) {
cfg.setProperty("hibernate.default_entity_mode", "dynamic-map");
};
cfg.setProperty("hibernate.current_session_context_class", currentSessionContext);
cfg.setProperty("hibernate.show_sql", showSql .toString())
.setProperty("hibernate.connection.url", connectionUrl)
.setProperty("hibernate.connection.username", username)
.setProperty("hibernate.connection.password", password)
.setProperty("hibernate.connection.useUnicode", "true")
.setProperty("hibernate.connection.characterEncoding", "UTF-8")
.setProperty("hibernate.connection.charSet", "UTF-8")
.setProperty("hibernate.connection.driver_class", getDriverClass(dbType))
;
//TODO pluggable
if(c3p0) {
cfg
.setProperty("connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider")
.setProperty("hibernate.c3p0.acquire_increment", "3")
.setProperty("hibernate.c3p0.min_size", "30")
.setProperty("hibernate.c3p0.max_size", "100")
.setProperty("hibernate.c3p0.max_statements", "300")
.setProperty("hibernate.c3p0.acquireRetryAttempts", "2")
.setProperty("hibernate.c3p0.acquireRetryDelay", "450")
.setProperty("hibernate.c3p0.timeout", "5000")
.setProperty("hibernate.c3p0.idle_test", "300");
}
switch (dbType) {
case HSQLDB:
cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect")
.setProperty("hibernate.jdbc.batch_size", "0");
break;
case MYSQL:
cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
//.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver")
;
break;
case POSTGRESQL:
cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
cfg.registerTypeOverride( new PgDataObjectJsonType(), new String[]{"jsonDataObject"});
cfg.registerTypeOverride( new PgMapListJsonType(), new String[]{"jsonMapList"});
break;
default:
throw new IllegalStateException();
}
Properties properties = cfg.getProperties();
Environment.verifyProperties( properties );
for(String res : resources) {
cfg.addResource(res);
}
return cfg;
}
private DBType inferDbType() {
return connectionUrl.contains("mysql") ? DBType.MYSQL
: connectionUrl.contains("hsql") ? DBType.HSQLDB
: connectionUrl.contains("postgresql") ? DBType.POSTGRESQL
: DBType.UNKNOWN;
}
public void setConnectionUrl(String url) {
this.connectionUrl = url;
}
public void setUsername(String user) {
this.username = user;
}
public void setPassword(String pass) {
this.password = pass;
}
public void setShowSql(Boolean showSql) {
this.showSql = showSql;
}
private String getDriverClass(DBType dbType) {
switch (dbType) {
case HSQLDB:
return "org.hsqldb.jdbcDriver";
case MYSQL:
return "com.mysql.jdbc.Driver";
case POSTGRESQL:
return "org.postgresql.Driver";
default:
throw new IllegalStateException();
}
}
public DataSource getDataSource() throws PropertyVetoException {//TODO not c3p0 or configurable
if(ds == null) {
ds = new ComboPooledDataSource();
ds.setDriverClass(getDriverClass(inferDbType()));
ds.setJdbcUrl(connectionUrl);
ds.setUser(username);
ds.setPassword(password);
ds.setAcquireIncrement(3);
ds.setMinPoolSize(3);
ds.setMaxPoolSize(15);
ds.setMaxStatements(300);
ds.setAcquireRetryAttempts(2);
ds.setAcquireRetryDelay(450);
ds.setCheckoutTimeout(5000);
ds.setIdleConnectionTestPeriod(300);
}
return ds;
}
public void setResource(String resource) {
this.resources.clear();
this.resources.add(resource);
}
public void setResources(List<String> resources) {
this.resources.clear();
this.resources.addAll(resources);
}
private static final Set<String> ALLOWED_CURRENT_SESSION_CONTEXTS = new HashSet<>(asList("thread","managed","jta"));
public void setCurrentSessionContext(String currentSessionContext) {
illegalargument.assertTrue(ALLOWED_CURRENT_SESSION_CONTEXTS.contains(currentSessionContext), "unsupported currentSessionContext:"+currentSessionContext);
this.currentSessionContext = currentSessionContext;
}
}