/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.aries.samples.ariestrader.core;
import javax.sql.DataSource;
import org.apache.aries.samples.ariestrader.api.persistence.RunStatsDataBean;
import org.apache.aries.samples.ariestrader.util.Log;
import org.apache.aries.samples.ariestrader.util.MDBStats;
import org.apache.aries.samples.ariestrader.util.ServiceUtilities;
import org.apache.aries.samples.ariestrader.util.TradeConfig;
import org.apache.aries.samples.ariestrader.api.TradeDBManager;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* TradeDBManagerImpl centralizes and simplifies the DB
* configuration methods that are shared by some TradeServices
* implementations.
*
* @see
* org.apache.aries.samples.ariestrader.api.TradeDBManager
*/
public class TradeDBManagerImpl implements TradeDBManager {
private DataSource dataSource = null;
private static boolean initialized = false;
private static int connCount = 0;
private static Integer lock = new Integer(0);
/**
* Zero arg constructor for TradeDBManagerImpl
*/
public TradeDBManagerImpl() {
}
/**
* set data source
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Return a String containing the DBProductName configured for
* the current DataSource
*
* used by TradeBuildDB
*
* @return A String of the currently configured DataSource
*
*/
public String checkDBProductName() throws Exception {
Connection conn = null;
String dbProductName = null;
try {
if (Log.doTrace())
Log.traceEnter("TradeDBManagerImpl:checkDBProductName");
conn = getConn();
DatabaseMetaData dbmd = conn.getMetaData();
dbProductName = dbmd.getDatabaseProductName();
}
catch (SQLException e) {
Log.error(e, "TradeDBManagerImpl:checkDBProductName() -- Error checking the AriesTrader Database Product Name");
}
finally {
releaseConn(conn);
}
return dbProductName;
}
/**
* Recreate DataBase Tables for AriesTrader
*
* used by TradeBuildDB
*
* @return boolean of success/failure in recreate of DB tables
*
*/
public boolean recreateDBTables(Object[] sqlBuffer, java.io.PrintWriter out) throws Exception {
// Clear MDB Statistics
MDBStats.getInstance().reset();
Connection conn = null;
boolean success = false;
try {
if (Log.doTrace())
Log.traceEnter("TradeDBManagerImpl:recreateDBTables");
conn = getConn();
Statement stmt = conn.createStatement();
int bufferLength = sqlBuffer.length;
for (int i = 0; i < bufferLength; i++) {
try {
stmt.executeUpdate((String) sqlBuffer[i]);
}
catch (SQLException ex) {
// Ignore DROP statements as tables won't always exist.
if (((String) sqlBuffer[i]).indexOf("DROP TABLE") < 0) {
Log.error("TradeDBManagerImpl:recreateDBTables SQL Exception thrown on executing the foll sql command: "
+ sqlBuffer[i], ex);
out.println("<BR>SQL Exception thrown on executing the foll sql command: <I>" + sqlBuffer[i]
+ "</I> . Check log for details.</BR>");
}
}
}
stmt.close();
commit(conn);
success = true;
}
catch (Exception e) {
Log.error(e, "TradeDBManagerImpl:recreateDBTables() -- Error dropping and recreating the database tables");
}
finally {
releaseConn(conn);
}
return success;
}
/**
* Reset the statistics for the Test AriesTrader Scenario
*
* used by TradeConfigServlet
*
* @return the RunStatsDataBean
*
*/
public RunStatsDataBean resetTrade(boolean deleteAll) throws Exception {
// Clear MDB Statistics
MDBStats.getInstance().reset();
// Reset Trade
RunStatsDataBean runStatsData = new RunStatsDataBean();
Connection conn = null;
try {
if (Log.doTrace())
Log.traceEnter("TradeDBManagerImpl:resetTrade deleteAll rows=" + deleteAll);
conn = getConn();
PreparedStatement stmt = null;
ResultSet rs = null;
if (deleteAll) {
try {
stmt = getStatement(conn, "delete from quoteejb");
stmt.executeUpdate();
stmt.close();
stmt = getStatement(conn, "delete from accountejb");
stmt.executeUpdate();
stmt.close();
stmt = getStatement(conn, "delete from accountprofileejb");
stmt.executeUpdate();
stmt.close();
stmt = getStatement(conn, "delete from holdingejb");
stmt.executeUpdate();
stmt.close();
stmt = getStatement(conn, "delete from orderejb");
stmt.executeUpdate();
stmt.close();
// FUTURE: - DuplicateKeyException - For now, don't start at
// zero as KeySequenceDirect and KeySequenceBean will still
// give out
// the cached Block and then notice this change. Better
// solution is
// to signal both classes to drop their cached blocks
// stmt = getStatement(conn, "delete from keygenejb");
// stmt.executeUpdate();
// stmt.close();
commit(conn);
}
catch (Exception e) {
Log.error(e, "TradeDBManagerImpl:resetTrade(deleteAll) -- Error deleting Trade users and stock from the Trade database");
}
return runStatsData;
}
stmt = getStatement(conn, "delete from holdingejb where holdingejb.account_accountid is null");
stmt.executeUpdate();
stmt.close();
// Count and Delete newly registered users (users w/ id that start
// "ru:%":
stmt = getStatement(conn, "delete from accountprofileejb where userid like 'ru:%'");
stmt.executeUpdate();
stmt.close();
stmt = getStatement(conn,
"delete from orderejb where account_accountid in (select accountid from accountejb a where a.profile_userid like 'ru:%')");
stmt.executeUpdate();
stmt.close();
stmt = getStatement(conn,
"delete from holdingejb where account_accountid in (select accountid from accountejb a where a.profile_userid like 'ru:%')");
stmt.executeUpdate();
stmt.close();
stmt = getStatement(conn, "delete from accountejb where profile_userid like 'ru:%'");
int newUserCount = stmt.executeUpdate();
runStatsData.setNewUserCount(newUserCount);
stmt.close();
// Count of trade users
stmt = getStatement(conn,
"select count(accountid) as \"tradeUserCount\" from accountejb a where a.profile_userid like 'uid:%'");
rs = stmt.executeQuery();
rs.next();
int tradeUserCount = rs.getInt("tradeUserCount");
runStatsData.setTradeUserCount(tradeUserCount);
stmt.close();
rs.close();
// Count of trade stocks
stmt = getStatement(conn,
"select count(symbol) as \"tradeStockCount\" from quoteejb a where a.symbol like 's:%'");
rs = stmt.executeQuery();
rs.next();
int tradeStockCount = rs.getInt("tradeStockCount");
runStatsData.setTradeStockCount(tradeStockCount);
stmt.close();
// Count of trade users login, logout
stmt = getStatement(conn,
"select sum(loginCount) as \"sumLoginCount\", sum(logoutCount) as \"sumLogoutCount\" from accountejb a where a.profile_userID like 'uid:%'");
rs = stmt.executeQuery();
rs.next();
int sumLoginCount = rs.getInt("sumLoginCount");
int sumLogoutCount = rs.getInt("sumLogoutCount");
runStatsData.setSumLoginCount(sumLoginCount);
runStatsData.setSumLogoutCount(sumLogoutCount);
stmt.close();
rs.close();
// Update logoutcount and loginCount back to zero
stmt =
getStatement(conn, "update accountejb set logoutCount=0,loginCount=0 where profile_userID like 'uid:%'");
stmt.executeUpdate();
stmt.close();
// count holdings for trade users
stmt = getStatement(conn,
"select count(holdingid) as \"holdingCount\" from holdingejb h where h.account_accountid in "
+ "(select accountid from accountejb a where a.profile_userid like 'uid:%')");
rs = stmt.executeQuery();
rs.next();
int holdingCount = rs.getInt("holdingCount");
runStatsData.setHoldingCount(holdingCount);
stmt.close();
rs.close();
// count orders for trade users
stmt = getStatement(conn,
"select count(orderid) as \"orderCount\" from orderejb o where o.account_accountid in "
+ "(select accountid from accountejb a where a.profile_userid like 'uid:%')");
rs = stmt.executeQuery();
rs.next();
int orderCount = rs.getInt("orderCount");
runStatsData.setOrderCount(orderCount);
stmt.close();
rs.close();
// count orders by type for trade users
stmt = getStatement(conn,
"select count(orderid) \"buyOrderCount\"from orderejb o where (o.account_accountid in "
+ "(select accountid from accountejb a where a.profile_userid like 'uid:%')) AND "
+ " (o.orderType='buy')");
rs = stmt.executeQuery();
rs.next();
int buyOrderCount = rs.getInt("buyOrderCount");
runStatsData.setBuyOrderCount(buyOrderCount);
stmt.close();
rs.close();
// count orders by type for trade users
stmt = getStatement(conn,
"select count(orderid) \"sellOrderCount\"from orderejb o where (o.account_accountid in "
+ "(select accountid from accountejb a where a.profile_userid like 'uid:%')) AND "
+ " (o.orderType='sell')");
rs = stmt.executeQuery();
rs.next();
int sellOrderCount = rs.getInt("sellOrderCount");
runStatsData.setSellOrderCount(sellOrderCount);
stmt.close();
rs.close();
// Delete cancelled orders
stmt = getStatement(conn, "delete from orderejb where orderStatus='cancelled'");
int cancelledOrderCount = stmt.executeUpdate();
runStatsData.setCancelledOrderCount(cancelledOrderCount);
stmt.close();
rs.close();
// count open orders by type for trade users
stmt = getStatement(conn,
"select count(orderid) \"openOrderCount\"from orderejb o where (o.account_accountid in "
+ "(select accountid from accountejb a where a.profile_userid like 'uid:%')) AND "
+ " (o.orderStatus='open')");
rs = stmt.executeQuery();
rs.next();
int openOrderCount = rs.getInt("openOrderCount");
runStatsData.setOpenOrderCount(openOrderCount);
stmt.close();
rs.close();
// Delete orders for holding which have been purchased and sold
stmt = getStatement(conn, "delete from orderejb where holding_holdingid is null");
int deletedOrderCount = stmt.executeUpdate();
runStatsData.setDeletedOrderCount(deletedOrderCount);
stmt.close();
rs.close();
commit(conn);
System.out.println("TradeDBManagerImpl:reset Run stats data\n\n" + runStatsData);
}
catch (Exception e) {
Log.error(e, "Failed to reset Trade");
rollBack(conn, e);
throw e;
}
finally {
releaseConn(conn);
}
return runStatsData;
}
private void releaseConn(Connection conn) throws Exception {
try {
if (conn != null) {
conn.close();
if (Log.doTrace()) {
synchronized (lock) {
connCount--;
}
Log.trace("TradeDBManagerImpl:releaseConn -- connection closed, connCount=" + connCount);
}
}
}
catch (Exception e) {
Log.error("TradeDBManagerImpl:releaseConnection -- failed to close connection", e);
}
}
/*
* Lookup the TradeData DataSource
*/
private void lookupDataSource() throws Exception {
if (dataSource == null) {
dataSource = (DataSource) ServiceUtilities.getOSGIService(DataSource.class.getName(),TradeConfig.OSGI_DS_NAME_FILTER);
}
}
/*
* Allocate a new connection to the datasource
*/
private Connection getConn() throws Exception {
Connection conn = null;
lookupDataSource();
conn = dataSource.getConnection();
conn.setAutoCommit(false);
if (Log.doTrace()) {
synchronized (lock) {
connCount++;
}
Log.trace("TradeDBManagerImpl:getConn -- new connection allocated, IsolationLevel="
+ conn.getTransactionIsolation() + " connectionCount = " + connCount);
}
return conn;
}
/*
* Commit the provided connection
*/
private void commit(Connection conn) throws Exception {
if (conn != null)
conn.commit();
}
/*
* Rollback the statement for the given connection
*/
private void rollBack(Connection conn, Exception e) throws Exception {
Log.log("TradeDBManagerImpl:rollBack -- rolling back conn due to previously caught exception");
if (conn != null)
conn.rollback();
else
throw e; // Throw the exception
}
/*
* Allocate a new prepared statement for this connection
*/
private PreparedStatement getStatement(Connection conn, String sql) throws Exception {
return conn.prepareStatement(sql);
}
public void init() {
if (initialized)
return;
if (Log.doTrace())
Log.trace("TradeDBManagerImpl:init -- *** initializing");
if (Log.doTrace())
Log.trace("TradeDBManagerImpl:init -- +++ initialized");
initialized = true;
}
public void destroy() {
try {
Log.trace("TradeDBManagerImpl:destroy");
if (!initialized)
return;
}
catch (Exception e) {
Log.error("TradeDBManagerImpl:destroy", e);
}
}
}