package org.openlca.core.database.mysql;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import org.eclipse.persistence.jpa.PersistenceProvider;
import org.openlca.core.database.BaseDao;
import org.openlca.core.database.Daos;
import org.openlca.core.database.DatabaseException;
import org.openlca.core.database.DbUtils;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.Notifiable;
import org.openlca.core.model.AbstractEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
/**
* IDatabase implementation for MySQL database. The URL schema is
* "jdbc:mysql://" [host] ":" [port] "/" [database]
*/
public class MySQLDatabase extends Notifiable implements IDatabase {
private Logger log = LoggerFactory.getLogger(this.getClass());
private EntityManagerFactory entityFactory;
private String url;
private String user;
private String password;
private HikariDataSource connectionPool;
private final String persistenceUnit;
private File fileStorageLocation;
public MySQLDatabase(String url, String user, String password) {
this(url, user, password, "openLCA");
}
public MySQLDatabase(String url, String user, String password,
String persistenceUnit) {
this.persistenceUnit = persistenceUnit;
this.url = url;
if (!this.url.contains("rewriteBatchedStatements")
&& this.url.contains("useServerPrepStmts")) {
this.url += "&rewriteBatchedStatements=true"
+ "&useServerPrepStmts=false";
log.trace("modified URL optimized for batch updates: {}", this.url);
}
this.user = user;
this.password = password;
connect();
}
private void connect() {
log.trace("Connect to database mysql: {} @ {}", user, url);
Map<Object, Object> map = new HashMap<>();
map.put("javax.persistence.jdbc.url", url);
map.put("javax.persistence.jdbc.user", user);
map.put("javax.persistence.jdbc.password", password);
map.put("javax.persistence.jdbc.driver", "com.mysql.jdbc.Driver");
map.put("eclipselink.classloader", getClass().getClassLoader());
map.put("eclipselink.target-database", "MySQL");
entityFactory = new PersistenceProvider().createEntityManagerFactory(
persistenceUnit, map);
initConnectionPool();
}
private void initConnectionPool() {
try {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(url);
config.setUsername(user);
config.setPassword(password);
connectionPool = new HikariDataSource(config);
} catch (Exception e) {
log.error("failed to initialize connection pool", e);
throw new DatabaseException("Could not create a connection", e);
}
}
@Override
public File getFileStorageLocation() {
return fileStorageLocation;
}
public void setFileStorageLocation(File fileStorageLocation) {
this.fileStorageLocation = fileStorageLocation;
}
@Override
public EntityManagerFactory getEntityFactory() {
return entityFactory;
}
@Override
public Connection createConnection() {
log.trace("create connection mysql: {} @ {}", user, url);
try {
if (connectionPool != null) {
Connection con = connectionPool.getConnection();
con.setAutoCommit(false);
return con;
} else {
log.warn("no connection pool set up for {}", url);
return DriverManager.getConnection(url, user, password);
}
} catch (Exception e) {
log.error("Failed to create database connection", e);
return null;
}
}
@Override
public void close() {
log.trace("close database mysql: {} @ {}", user, url);
try {
if (entityFactory != null && entityFactory.isOpen())
entityFactory.close();
if (connectionPool != null)
connectionPool.close();
} catch (Exception e) {
log.error("failed to close database", e);
} finally {
entityFactory = null;
connectionPool = null;
}
}
@Override
public <T extends AbstractEntity> BaseDao<T> createDao(Class<T> clazz) {
return Daos.createBaseDao(this, clazz);
}
@Override
public String getName() {
if (url == null)
return null;
String[] parts = url.split("/");
if (parts.length < 2)
return null;
return parts[parts.length - 1].trim();
}
@Override
public int getVersion() {
return DbUtils.getVersion(this);
}
}