Java tutorial
/** * This file is part of Aion X Emu <aionxemu.com> * * This is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This software 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 Public License for more details. * * You should have received a copy of the GNU Lesser Public License * along with this software. If not, see <http://www.gnu.org/licenses/>. */ package com.aionemu.commons.database; import com.aionemu.commons.configuration.ConfigurableProcessor; import com.aionemu.commons.utils.PropertiesUtils; import org.apache.commons.dbcp.ConnectionFactory; import org.apache.commons.dbcp.DriverManagerConnectionFactory; import org.apache.commons.dbcp.PoolingDataSource; import org.apache.commons.pool.impl.GenericObjectPool; import org.apache.log4j.Logger; import javax.sql.DataSource; import java.io.IOException; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.util.Properties; /** * <b>Database Factory</b><br> * <br> * This file is used for creating a pool of connections for the server.<br> * It utilizes database.properties and creates a pool of connections and automatically recycles them when closed.<br> * <br> * DB.java utilizes the class.<br> * <br> * <p/> * This class depends on file {@value com.aionemu.commons.database.DatabaseConfig#CONFIG_FILE}. * * @author Disturbing * @author SoulKeeper */ public class DatabaseFactory { /** * Logger for this class */ private static final Logger log = Logger.getLogger(DatabaseFactory.class); /** * Data Source Generates all Connections This variable is also used as indicator for "initialized" state of * DatabaseFactory */ private static DataSource dataSource; /** * Connection Pool holds all connections - Idle or Active */ private static GenericObjectPool connectionPool; /** * Returns name of the database that is used * <p/> * For isntance, MySQL returns "MySQL" */ private static String databaseName; /** * Retursn major version that is used For instance, MySQL 5.0.51 community edition returns 5 */ private static int databaseMajorVersion; /** * Retursn minor version that is used For instance, MySQL 5.0.51 community edition returns 0 */ private static int databaseMinorVersion; /** * Initializes DatabaseFactory. */ public synchronized static void init() { init(""); } public synchronized static void init(String configFilePath) { if (dataSource != null) { return; } if (!configFilePath.equals("")) { try { Properties dbProps = PropertiesUtils.load(configFilePath); ConfigurableProcessor.process(DatabaseConfig.class, dbProps); } catch (IOException ex) { log.fatal("Cannot load database config", ex); } } try { DatabaseConfig.DATABASE_DRIVER.newInstance(); } catch (Exception e) { log.fatal("Error obtaining DB driver", e); throw new Error("DB Driver doesnt exist!"); } connectionPool = new GenericObjectPool(); if (DatabaseConfig.DATABASE_CONNECTIONS_MIN > DatabaseConfig.DATABASE_CONNECTIONS_MAX) { log.error("Please check your database configuration. Minimum amount of connections is > maximum"); DatabaseConfig.DATABASE_CONNECTIONS_MAX = DatabaseConfig.DATABASE_CONNECTIONS_MIN; } connectionPool.setMaxIdle(DatabaseConfig.DATABASE_CONNECTIONS_MIN); connectionPool.setMaxActive(DatabaseConfig.DATABASE_CONNECTIONS_MAX); /* test if connection is still valid before returning */ //connectionPool.setTestOnBorrow(true); try { dataSource = setupDataSource(); Connection c = getConnection(); DatabaseMetaData dmd = c.getMetaData(); databaseName = dmd.getDatabaseProductName(); databaseMajorVersion = dmd.getDatabaseMajorVersion(); databaseMinorVersion = dmd.getDatabaseMinorVersion(); c.close(); } catch (Exception e) { log.fatal("Error with connection string: " + DatabaseConfig.DATABASE_URL, e); throw new Error("DatabaseFactory not initialized!"); } log.info("Successfully connected to database"); } /** * Sets up Connection Factory and Pool * * @return DataSource configured datasource * @throws Exception if initialization failed */ private static DataSource setupDataSource() throws Exception { // Create Connection Factory ConnectionFactory conFactory = new DriverManagerConnectionFactory(DatabaseConfig.DATABASE_URL, DatabaseConfig.DATABASE_USER, DatabaseConfig.DATABASE_PASSWORD); // Makes Connection Factory Pool-able (Wrapper for two objects) // We are using our own implementation of PoolableConnectionFactory that use 1.6 Connection.isValid(timeout) for // validation check instead dbcp manual query. new PoolableConnectionFactoryAE(conFactory, connectionPool, null, 1, false, true); // Create data source to utilize Factory and Pool return new PoolingDataSource(connectionPool); } /** * Returns an active connection from pool. This function utilizes the dataSource which grabs an object from the * ObjectPool within its limits. The GenericObjectPool.borrowObject()' function utilized in * 'DataSource.getConnection()' does not allow any connections to be returned as null, thus a null check is not * needed. Throws SQLException in case of a Failed Connection * * @return Connection pooled connection * @throws java.sql.SQLException if can't get connection */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } /** * Returns number of active connections in the pool. * * @return int Active DB Connections */ public int getActiveConnections() { return connectionPool.getNumActive(); } /** * Returns number of Idle connections. Idle connections represent the number of instances in Database Connections * that have once been connected and now are closed and ready for re-use. The 'getConnection' function will grab * idle connections before creating new ones. * * @return int Idle DB Connections */ public int getIdleConnections() { return connectionPool.getNumIdle(); } /** * Shuts down pool and closes connections */ public static synchronized void shutdown() { try { connectionPool.close(); } catch (Exception e) { log.warn("Failed to shutdown DatabaseFactory", e); } // set datasource to null so we can call init() once more... dataSource = null; } public static void close(Connection con) { if (con == null) return; try { con.close(); } catch (SQLException e) { log.warn("DatabaseFactory: Failed to close database connection!", e); } } /** * Returns database name. For instance MySQL 5.0.51 community edition returns MySQL * * @return database name that is used. */ public static String getDatabaseName() { return databaseName; } /** * Returns database version. For instance MySQL 5.0.51 community edition returns 5 * * @return database major version */ public static int getDatabaseMajorVersion() { return databaseMajorVersion; } /** * Returns database minor version. For instance MySQL 5.0.51 community edition reutnrs 0 * * @return database minor version */ public static int getDatabaseMinorVersion() { return databaseMinorVersion; } /** * Default constructor. */ private DatabaseFactory() { // } }