You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by ge...@apache.org on 2005/09/20 18:08:17 UTC

svn commit: r290479 [4/16] - in /geronimo/trunk/sandbox/daytrader: ./ bin/ derby/ modules/ modules/core/ modules/core/src/ modules/core/src/conf/ modules/core/src/java/ modules/core/src/java/org/ modules/core/src/java/org/apache/ modules/core/src/java/...

Added: geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/direct/TradeDirect.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/direct/TradeDirect.java?rev=290479&view=auto
==============================================================================
--- geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/direct/TradeDirect.java (added)
+++ geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/direct/TradeDirect.java Tue Sep 20 09:07:08 2005
@@ -0,0 +1,2312 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation or its licensors, as applicable 
+ *
+ *  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 org.apache.geronimo.samples.daytrader.direct;
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.ArrayList;
+import javax.naming.InitialContext;
+import javax.transaction.UserTransaction;
+import javax.jms.*;
+
+import javax.sql.DataSource;
+
+import org.apache.geronimo.samples.daytrader.ejb.Trade;
+import org.apache.geronimo.samples.daytrader.ejb.TradeHome;
+import org.apache.geronimo.samples.daytrader.util.*;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.Timestamp;
+
+import org.apache.geronimo.samples.daytrader.*;
+
+/**
+  * TradeDirect uses direct JDBC and JMS access to a <code>javax.sql.DataSource</code> to implement the business methods 
+  * of the Trade online broker application. These business methods represent the features and operations that 
+  * can be performed by customers of the brokerage such as login, logout, get a stock quote, buy or sell a stock, etc.
+  * and are specified in the {@link org.apache.geronimo.samples.daytrader.TradeServices} interface
+  *
+  * Note: In order for this class to be thread-safe, a new TradeJDBC must be created
+  * for each call to a method from the TradeInterface interface.  Otherwise, pooled
+  * connections may not be released.
+  *
+  * @see org.apache.geronimo.samples.daytrader.TradeServices
+  * @see org.apache.geronimo.samples.daytrader.ejb.Trade
+  *
+  */
+
+public class TradeDirect implements TradeServices
+			
+{
+	
+	private static String dsName = TradeConfig.DATASOURCE;
+	private static DataSource datasource = null;
+	private static BigDecimal ZERO = new BigDecimal(0.0);
+	private boolean inGlobalTxn = false;
+
+	/**
+	 * Zero arg constructor for TradeDirect
+	 */
+	public TradeDirect() {
+	    if (initialized==false) init();
+	}
+
+	/**
+	 * @see TradeServices#getMarketSummary()
+	 */
+	public MarketSummaryDataBean getMarketSummary() throws Exception {
+		
+		MarketSummaryDataBean marketSummaryData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getMarketSummary");
+			
+			conn = getConn();
+            PreparedStatement stmt = getStatement(conn, getTSIAQuotesOrderByChangeSQL, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
+            
+		    ArrayList topGainersData = new ArrayList(5);
+		    ArrayList topLosersData = new ArrayList(5);		    
+
+			ResultSet rs = stmt.executeQuery();
+			
+			int count = 0; 
+			while (rs.next() && (count++ < 5) )
+			{
+				QuoteDataBean quoteData = getQuoteDataFromResultSet(rs);
+				topLosersData.add(quoteData);
+			}
+			
+			
+			stmt.close();
+            stmt = getStatement(conn, "select * from quoteejb q where q.symbol like 's:1__' order by q.change1 DESC", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );			
+			rs = stmt.executeQuery();
+
+			count = 0; 
+			while (rs.next() && (count++ < 5) )
+			{
+				QuoteDataBean quoteData = getQuoteDataFromResultSet(rs);
+				topGainersData.add(quoteData);
+			}
+			         
+		
+			/*
+			rs.last();
+			count = 0;
+			while (rs.previous() && (count++ < 5) )
+			{
+				QuoteDataBean quoteData = getQuoteDataFromResultSet(rs);
+				topGainersData.add(quoteData);
+			}*/
+			
+			stmt.close();
+			
+			stmt = getStatement(conn, getTSIASQL);
+			rs = stmt.executeQuery();
+			BigDecimal TSIA=ZERO;
+			if (!rs.next() )  
+				Log.error("TradeDirect:getMarketSummary -- error w/ getTSIASQL -- no results");
+			else 
+				TSIA = rs.getBigDecimal("TSIA");
+			stmt.close();
+
+			
+			stmt = getStatement(conn, getOpenTSIASQL);
+			rs = stmt.executeQuery();
+			BigDecimal openTSIA = ZERO;
+			if (!rs.next() )  
+				Log.error("TradeDirect:getMarketSummary -- error w/ getOpenTSIASQL -- no results");
+			else 
+				openTSIA = rs.getBigDecimal("openTSIA");
+			stmt.close();
+
+			stmt = getStatement(conn, getTSIATotalVolumeSQL);
+			rs = stmt.executeQuery();
+			double volume=0.0;
+			if (!rs.next() ) 
+				Log.error("TradeDirect:getMarketSummary -- error w/ getTSIATotalVolumeSQL -- no results");
+			else 
+				volume = rs.getDouble("totalVolume");
+			stmt.close();
+			
+			commit(conn);
+				
+			marketSummaryData = new MarketSummaryDataBean(TSIA, openTSIA, volume, topGainersData, topLosersData);
+
+		}
+
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:login -- error logging in user", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return marketSummaryData;		
+
+	}
+
+	/**
+	 * @see TradeServices#buy(String, String, double)
+	 */
+	public OrderDataBean buy(String userID, String symbol, double quantity, int orderProcessingMode)
+		throws Exception {
+
+		Connection conn=null;
+		OrderDataBean orderData = null;
+		UserTransaction txn = null;
+		
+		/*
+		 * total = (quantity * purchasePrice) + orderFee
+		 */
+		BigDecimal total;
+		
+	
+		try
+		{
+			if (Log.doTrace()) 
+				Log.trace("TradeDirect:buy", userID, symbol, new Double(quantity));
+			
+			if ( orderProcessingMode == TradeConfig.ASYNCH_2PHASE )
+			{
+				if ( Log.doTrace() )
+					Log.trace("TradeDirect:buy create/begin global transaction");		
+				//FUTURE the UserTransaction be looked up once
+				txn = (javax.transaction.UserTransaction) context.lookup("java:comp/UserTransaction");
+				txn.begin();
+				setInGlobalTxn(true);
+			}
+		
+			conn = getConn();
+			
+			AccountDataBean accountData = getAccountData(conn, userID);
+			QuoteDataBean quoteData = getQuoteData(conn, symbol);
+			HoldingDataBean holdingData = null; // the buy operation will create the holding
+
+			orderData = createOrder(conn, accountData, quoteData, holdingData, "buy", quantity);
+
+			//Update -- account should be credited during completeOrder
+			BigDecimal price = quoteData.getPrice();
+			BigDecimal orderFee = orderData.getOrderFee();
+			total   = (new BigDecimal(quantity).multiply(price)).add(orderFee);
+			// subtract total from account balance
+			creditAccountBalance(conn, accountData, total.negate());
+
+			try {
+				if (orderProcessingMode == TradeConfig.SYNCH) 
+					completeOrder(conn, orderData.getOrderID());
+				else if (orderProcessingMode == TradeConfig.ASYNCH)
+					queueOrder(orderData.getOrderID(), false);	// 1-phase commit
+				else //TradeConfig.ASYNC_2PHASE
+					queueOrder(orderData.getOrderID(), true);	// 2-phase commit
+			}
+			catch (JMSException je)
+			{
+				Log.error("TradeBean:buy("+userID+","+symbol+","+quantity+") --> failed to queueOrder", je);
+				/* On exception - cancel the order */
+
+				cancelOrder(conn, orderData.getOrderID());	
+			}
+			
+			if (txn != null) {
+				if ( Log.doTrace() )
+					Log.trace("TradeDirect:buy committing global transaction");		
+				txn.commit();
+				setInGlobalTxn(false);
+			}
+			else
+				commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:buy error - rolling back", e);
+			if ( getInGlobalTxn() )
+				txn.rollback();
+			else
+				rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+
+		return orderData;		
+	}
+
+	/**
+	 * @see TradeServices#sell(String, Integer)
+	 */
+	public OrderDataBean sell(String userID, Integer holdingID, int orderProcessingMode)
+		throws Exception {
+		Connection conn=null;
+		OrderDataBean orderData = null;
+		UserTransaction txn = null;
+		
+		/*
+		 * total = (quantity * purchasePrice) + orderFee
+		 */
+		BigDecimal total;
+		
+		try
+		{
+			if (Log.doTrace()) 
+				Log.trace("TradeDirect:sell", userID, holdingID);
+
+			if ( orderProcessingMode == TradeConfig.ASYNCH_2PHASE )
+			{
+				if ( Log.doTrace() )
+					Log.trace("TradeDirect:sell create/begin global transaction");		
+				//FUTURE the UserTransaction be looked up once
+
+				txn = (javax.transaction.UserTransaction) context.lookup("java:comp/UserTransaction");
+				txn.begin();
+				setInGlobalTxn(true);
+			}
+			
+			conn = getConn();
+			
+			AccountDataBean accountData = getAccountData(conn, userID);
+			HoldingDataBean holdingData = getHoldingData(conn, holdingID.intValue() );
+			QuoteDataBean quoteData = null;
+			if ( holdingData != null) quoteData = getQuoteData(conn, holdingData.getQuoteID());
+			
+			if ( (accountData==null) || (holdingData==null) || (quoteData==null) )
+			{
+				String error = "TradeDirect:sell -- error selling stock -- unable to find:  \n\taccount=" +accountData + "\n\tholding=" + holdingData + "\n\tquote="+quoteData + "\nfor user: " + userID + " and holdingID: " + holdingID;
+				Log.error(error);
+				if ( getInGlobalTxn() )
+					txn.rollback();
+				else
+					rollBack(conn, new Exception(error));							
+				return orderData;
+			}
+
+			double		 quantity = holdingData.getQuantity();
+
+			orderData = createOrder(conn, accountData, quoteData, holdingData, "sell", quantity);
+			
+			// Set the holdingSymbol purchaseDate to selling to signify the sell is "inflight"
+			updateHoldingStatus(conn, holdingData.getHoldingID(), holdingData.getQuoteID());		
+
+			//UPDATE -- account should be credited during completeOrder
+			BigDecimal price = quoteData.getPrice();
+			BigDecimal orderFee = orderData.getOrderFee();
+			total   = (new BigDecimal(quantity).multiply(price)).subtract(orderFee);
+			creditAccountBalance(conn, accountData, total);
+
+			try {
+				if (orderProcessingMode == TradeConfig.SYNCH) 
+					completeOrder(conn, orderData.getOrderID());
+				else if (orderProcessingMode == TradeConfig.ASYNCH)
+					queueOrder(orderData.getOrderID(), false);  // 1-phase commit
+				else //TradeConfig.ASYNC_2PHASE
+					queueOrder(orderData.getOrderID(), true);      // 2-phase commit
+			}
+			catch (JMSException je)
+			{
+				Log.error("TradeBean:sell("+userID+","+holdingID+") --> failed to queueOrder", je);
+				/* On exception - cancel the order */
+
+				cancelOrder(conn, orderData.getOrderID());	
+			}
+			if (txn != null) {
+				if ( Log.doTrace() )
+					Log.trace("TradeDirect:sell committing global transaction");		
+				txn.commit();
+				setInGlobalTxn(false);
+			}
+			else	
+				commit(conn);			
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:sell error", e);
+			if ( getInGlobalTxn() )
+				txn.rollback();
+			else
+				rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		
+		return orderData;		
+	}
+
+	/**
+	 * @see TradeServices#queueOrder(Integer)
+	 */
+	public void queueOrder(Integer orderID, boolean twoPhase) throws Exception 
+	{
+		if (Log.doTrace() ) Log.trace("TradeDirect:queueOrder", orderID);
+
+		javax.jms.Connection conn = null;	
+		Session sess = null;
+	
+		try 
+		{	
+			conn = qConnFactory.createConnection();		
+			sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+			MessageProducer producer = sess.createProducer(queue);
+
+			TextMessage   message = sess.createTextMessage();
+
+			String command= "neworder";
+			message.setStringProperty("command", command);
+			message.setIntProperty("orderID", orderID.intValue());
+			message.setBooleanProperty("twoPhase", twoPhase);
+			message.setBooleanProperty("direct", true);
+			message.setLongProperty("publishTime", System.currentTimeMillis());					
+			message.setText("neworder: orderID="+orderID + " runtimeMode=Direct twoPhase="+twoPhase);
+
+			if (Log.doTrace()) 
+				Log.trace("TradeDirectBean:queueOrder Sending message: " + message.getText());
+			producer.send(message);
+			sess.close();
+		}
+		
+		catch (Exception e)
+		{
+			throw e; // pass the exception back
+		}
+		
+		finally
+		{
+			if (sess != null)
+				sess.close();
+		}
+	}
+
+
+	/**
+	 * @see TradeServices#completeOrder(Integer)
+	 */
+	public OrderDataBean completeOrder(Integer orderID, boolean twoPhase) throws Exception 
+	{
+		OrderDataBean orderData = null;
+		Connection conn=null;
+
+		if (!twoPhase)
+		{
+			if (Log.doTrace())
+				Log.trace("TradeDirect:completeOrder -- completing order in 1-phase, calling tradeEJB to start new txn. orderID="+orderID);
+			return tradeEJB.completeOrderOnePhaseDirect(orderID);
+		}		
+		try  //twoPhase
+		{
+
+			if (Log.doTrace()) Log.trace("TradeDirect:completeOrder", orderID);
+			setInGlobalTxn(twoPhase);
+			conn = getConn();
+			orderData = completeOrder(conn, orderID);
+			commit(conn);
+
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:completeOrder -- error completing order", e);
+			rollBack(conn, e);
+			cancelOrder(orderID, twoPhase);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+			
+		return orderData;         	
+		
+	}
+	public OrderDataBean completeOrderOnePhase(Integer orderID) throws Exception 
+	{
+		OrderDataBean orderData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:completeOrderOnePhase", orderID);
+			setInGlobalTxn(false);
+			conn = getConn();
+			orderData = completeOrder(conn, orderID);
+
+			commit(conn);
+
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:completeOrderOnePhase -- error completing order", e);
+			rollBack(conn, e);
+			cancelOrder(orderID, false);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+				
+		return orderData;         	
+		
+	}
+
+	private OrderDataBean completeOrder(Connection conn, Integer orderID) 
+			throws Exception
+	{
+			
+		OrderDataBean orderData = null;
+		if (Log.doTrace()) Log.trace("TradeDirect:completeOrderInternal", orderID);
+
+		PreparedStatement stmt = getStatement(conn, getOrderSQL);
+        stmt.setInt(1, orderID.intValue());
+
+		ResultSet rs = stmt.executeQuery();
+
+		if ( !rs.next() )
+		{
+			Log.error("TradeDirect:completeOrder -- unable to find order: " + orderID);
+			stmt.close();
+			return orderData;
+		}
+		orderData = getOrderDataFromResultSet(rs);
+		
+		String orderType = orderData.getOrderType();
+		String orderStatus = orderData.getOrderStatus();
+		
+		//if (order.isCompleted())
+    	if ( (orderStatus.compareToIgnoreCase("completed") == 0) ||
+	         (orderStatus.compareToIgnoreCase("alertcompleted") == 0)    ||
+	         (orderStatus.compareToIgnoreCase("cancelled") == 0) ) 	         
+			throw new Exception("TradeDirect:completeOrder -- attempt to complete Order that is already completed");
+	
+		int        accountID = rs.getInt("account_accountID");
+		String       quoteID = rs.getString("quote_symbol");
+		int        holdingID = rs.getInt("holding_holdingID");
+		
+		BigDecimal     price = orderData.getPrice();
+		double	    quantity = orderData.getQuantity();
+		BigDecimal  orderFee = orderData.getOrderFee();
+
+		//get the data for the account and quote 
+		//the holding will be created for a buy or extracted for a sell
+
+
+		/* Use the AccountID and Quote Symbol from the Order
+			AccountDataBean accountData = getAccountData(accountID, conn);
+			QuoteDataBean     quoteData = getQuoteData(conn, quoteID);
+		 */
+		String 				 userID = getAccountProfileData(conn, new Integer(accountID)).getUserID();
+
+		HoldingDataBean holdingData = null;
+		
+		if (Log.doTrace()) Log.trace(
+				"TradeDirect:completeOrder--> Completing Order " + orderData.getOrderID()
+				 + "\n\t Order info: "   +   orderData
+				 + "\n\t Account info: " + accountID
+				 + "\n\t Quote info: "   +   quoteID);
+
+		//if (order.isBuy())
+	  	if ( orderType.compareToIgnoreCase("buy") == 0 )
+	  	{ 
+			/* Complete a Buy operation
+			 *	- create a new Holding for the Account
+			 *	- deduct the Order cost from the Account balance
+			 */
+	
+			holdingData = createHolding(conn, accountID, quoteID, quantity, price);
+			updateOrderHolding(conn, orderID.intValue(), holdingData.getHoldingID().intValue());
+		}
+		
+		//if (order.isSell()) {
+	  	if ( orderType.compareToIgnoreCase("sell") == 0 ) 
+	  	{	
+			/* Complete a Sell operation
+			 *	- remove the Holding from the Account
+			 *	- deposit the Order proceeds to the Account balance
+			 */	
+			holdingData = getHoldingData(conn, holdingID);
+			if ( holdingData == null )
+				Log.debug("TradeDirect:completeOrder:sell -- user: " + userID + " already sold holding: " + holdingID);			
+			else
+				removeHolding(conn, holdingID, orderID.intValue());		
+
+		}
+
+		updateOrderStatus(conn, orderData.getOrderID(), "closed");
+		
+		if (Log.doTrace()) Log.trace(
+			"TradeDirect:completeOrder--> Completed Order " + orderData.getOrderID()
+				 + "\n\t Order info: "   +   orderData
+				 + "\n\t Account info: " + accountID
+				 + "\n\t Quote info: "   +   quoteID
+				 + "\n\t Holding info: " + holdingData);
+
+		stmt.close();
+
+		commit(conn);
+
+		//signify this order for user userID is complete		
+		TradeAction tradeAction = new TradeAction(this);		
+		tradeAction.orderCompleted(userID, orderID);
+
+		return orderData;
+	}
+	
+	/**
+	 * @see TradeServices#cancelOrder(Integer, boolean)
+	 */
+	public void cancelOrder(Integer orderID, boolean twoPhase) 
+	throws Exception 
+	{
+		OrderDataBean orderData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:cancelOrder", orderID);
+			setInGlobalTxn(twoPhase);
+			conn = getConn();
+			cancelOrder(conn, orderID);
+			commit(conn);
+
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:cancelOrder -- error cancelling order: "+orderID, e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}		
+	}
+	public void cancelOrderOnePhase(Integer orderID) 
+	throws Exception 
+	{
+		OrderDataBean orderData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:cancelOrderOnePhase", orderID);
+			setInGlobalTxn(false);
+			conn = getConn();
+			cancelOrder(conn, orderID);
+			commit(conn);
+
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:cancelOrderOnePhase -- error cancelling order: "+orderID, e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}		
+	}	
+	private void cancelOrder(Connection conn, Integer orderID) 
+	throws Exception 
+	{
+		updateOrderStatus(conn, orderID, "cancelled");
+	}
+	
+
+	public void orderCompleted(String userID, Integer orderID) 
+	throws Exception
+	{
+		throw new UnsupportedOperationException("TradeDirect:orderCompleted method not supported");
+	}
+	
+
+	private HoldingDataBean createHolding(Connection conn, int accountID, String symbol, double quantity, BigDecimal purchasePrice) 
+		throws Exception 
+	{
+		HoldingDataBean holdingData = null;
+
+		Timestamp purchaseDate = new Timestamp(System.currentTimeMillis());
+		PreparedStatement stmt = getStatement(conn, createHoldingSQL);
+	
+		Integer holdingID = KeySequenceDirect.getNextID(conn, "holding", getInGlobalTxn());
+		stmt.setInt(1, holdingID.intValue());
+		stmt.setTimestamp(2, purchaseDate);
+		stmt.setBigDecimal(3, purchasePrice);
+		stmt.setDouble(4, quantity);
+		stmt.setString(5, symbol);
+		stmt.setInt(6, accountID);
+		int rowCount = stmt.executeUpdate();
+
+		stmt.close();
+				
+		return getHoldingData(conn, holdingID.intValue());
+	}
+	private void removeHolding(Connection conn, int holdingID, int orderID) 
+		throws Exception 
+	{
+		PreparedStatement stmt = getStatement(conn, removeHoldingSQL);
+	
+		stmt.setInt(1, holdingID);
+		int rowCount = stmt.executeUpdate();
+		stmt.close();	
+
+		// set the HoldingID to NULL for the purchase and sell order now that
+		// the holding as been removed		
+		stmt = getStatement(conn, removeHoldingFromOrderSQL);
+	
+		stmt.setInt(1, holdingID);
+		rowCount = stmt.executeUpdate();
+		stmt.close();	
+		
+	}
+	
+	private OrderDataBean createOrder(Connection conn, AccountDataBean accountData, QuoteDataBean quoteData, HoldingDataBean holdingData, String orderType, double quantity) 
+		throws Exception 
+	{
+		OrderDataBean orderData = null;
+
+		Timestamp currentDate = new Timestamp(System.currentTimeMillis());
+				
+		PreparedStatement stmt = getStatement(conn, createOrderSQL);
+	
+
+		Integer orderID = KeySequenceDirect.getNextID(conn, "order", getInGlobalTxn());
+		stmt.setInt(1, orderID.intValue());
+		stmt.setString(2, orderType);
+		stmt.setString(3, "open");
+		stmt.setTimestamp(4, currentDate);
+		stmt.setDouble(5, quantity);
+		stmt.setBigDecimal(6, quoteData.getPrice().setScale(FinancialUtils.SCALE, FinancialUtils.ROUND));
+		stmt.setBigDecimal(7, TradeConfig.getOrderFee(orderType));
+		stmt.setInt(8, accountData.getAccountID().intValue());
+		if (holdingData == null ) stmt.setNull(9, java.sql.Types.INTEGER);
+		else stmt.setInt(9, holdingData.getHoldingID().intValue());
+		stmt.setString(10, quoteData.getSymbol());		
+		int rowCount = stmt.executeUpdate();
+
+		stmt.close();
+				
+		return getOrderData(conn, orderID.intValue());
+	}
+	
+
+	/**
+	 * @see TradeServices#getOrders(String)
+	 */
+	public Collection getOrders(String userID) throws Exception {
+		Collection orderDataBeans = new ArrayList();
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getOrders", userID);
+			
+			conn = getConn();
+            PreparedStatement stmt = getStatement(conn, getOrdersByUserSQL);
+            stmt.setString(1, userID);
+
+			ResultSet rs = stmt.executeQuery();
+
+			//TODO: return top 5 orders for now -- next version will add a getAllOrders method
+			//      also need to get orders sorted by order id descending			
+			int i=0;
+			while ( (rs.next()) && (i++ < 5) )
+			{			
+				OrderDataBean orderData = getOrderDataFromResultSet(rs);
+				orderDataBeans.add(orderData);
+			}
+
+			stmt.close();
+			commit(conn);
+				
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getOrders -- error getting user orders", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return orderDataBeans;
+	}
+
+	/**
+	 * @see TradeServices#getClosedOrders(String)
+	 */
+	public Collection getClosedOrders(String userID) throws Exception {
+		Collection orderDataBeans = new ArrayList();
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getClosedOrders", userID);
+			
+			conn = getConn();
+            PreparedStatement stmt = getStatement(conn, getClosedOrdersSQL);
+            stmt.setString(1, userID);
+
+			ResultSet rs = stmt.executeQuery();
+
+			while ( rs.next() )
+			{			
+				OrderDataBean orderData = getOrderDataFromResultSet(rs);	
+				orderData.setOrderStatus("completed");
+				updateOrderStatus(conn, orderData.getOrderID(), orderData.getOrderStatus());
+				orderDataBeans.add(orderData);
+				
+			}
+
+			stmt.close();
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getOrders -- error getting user orders", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return orderDataBeans;
+	}
+
+	/**
+	 * @see TradeServices#createQuote(String, String, BigDecimal)
+	 */
+	public QuoteDataBean createQuote(
+		String symbol,
+		String companyName,
+		BigDecimal price)
+		throws Exception {
+		
+		QuoteDataBean quoteData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.traceEnter("TradeDirect:createQuote");
+			
+			price = price.setScale(FinancialUtils.SCALE, FinancialUtils.ROUND);
+			double volume=0.0, change=0.0;
+
+			conn = getConn();
+            PreparedStatement stmt = getStatement(conn, createQuoteSQL);
+            stmt.setString(1, symbol);			// symbol
+            stmt.setString(2, companyName);		// companyName
+            stmt.setDouble(3, volume);			// volume
+            stmt.setBigDecimal(4, price);		// price
+            stmt.setBigDecimal(5, price);		// open
+            stmt.setBigDecimal(6, price);		// low
+            stmt.setBigDecimal(7, price);		// high
+            stmt.setDouble(8, change);			// change
+
+			stmt.executeUpdate();
+			stmt.close();
+			commit(conn);
+				
+			quoteData = new QuoteDataBean(symbol, companyName, volume, price, price, price, price, change);
+			if (Log.doTrace()) Log.traceExit("TradeDirect:createQuote");
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:createQuote -- error creating quote", e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return quoteData;
+	}
+	
+	/**
+	 * @see TradeServices#getQuote(String)
+	 */
+	
+	public QuoteDataBean getQuote(String symbol) throws Exception {
+		QuoteDataBean quoteData = null;
+		Connection conn=null;
+		UserTransaction txn = null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getQuote", symbol);
+
+			conn = getConn();
+			quoteData = getQuote(conn, symbol);			
+			commit(conn);			
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getQuote -- error getting quote", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return quoteData;		
+	}
+	
+	private QuoteDataBean getQuote(Connection conn, String symbol) 
+	throws Exception 
+	{
+		QuoteDataBean quoteData = null;
+		PreparedStatement stmt = getStatement(conn, getQuoteSQL);
+		stmt.setString(1, symbol);			// symbol
+	
+		ResultSet rs = stmt.executeQuery();
+					
+		if ( !rs.next() )
+			Log.error("TradeDirect:getQuote -- failure no result.next() for symbol: " + symbol);
+				
+		else
+			quoteData = getQuoteDataFromResultSet(rs);
+
+		stmt.close();
+		
+		return quoteData;
+	}
+
+	private QuoteDataBean getQuoteForUpdate(Connection conn, String symbol) 
+	throws Exception 
+	{
+		QuoteDataBean quoteData = null;
+		PreparedStatement stmt = getStatement(conn, getQuoteForUpdateSQL);
+		stmt.setString(1, symbol);			// symbol
+	
+		ResultSet rs = stmt.executeQuery();
+					
+		if ( !rs.next() )
+			Log.error("TradeDirect:getQuote -- failure no result.next()");
+				
+		else
+			quoteData = getQuoteDataFromResultSet(rs);
+
+		stmt.close();
+		
+		return quoteData;
+	}	
+	
+	/**
+	 * @see TradeServices#getAllQuotes(String)
+	 */
+	public Collection getAllQuotes() throws Exception {
+		Collection quotes = new ArrayList();
+		QuoteDataBean quoteData = null;
+
+		Connection conn = null;
+		try {
+			conn = getConn();
+
+			PreparedStatement stmt = getStatement(conn, getAllQuotesSQL);
+	
+			ResultSet rs = stmt.executeQuery();
+
+			while (!rs.next()) {
+				quoteData = getQuoteDataFromResultSet(rs);
+				quotes.add(quoteData);
+			}
+
+			stmt.close();
+		}
+		catch (Exception e) {
+			Log.error("TradeDirect:getAllQuotes", e);
+			rollBack(conn, e);
+		}
+		finally {
+			releaseConn(conn);
+		}
+		
+		return quotes;
+	}
+
+	/**
+	 * @see TradeServices#getHoldings(String)
+	 */
+	public Collection getHoldings(String userID) throws Exception {
+		Collection holdingDataBeans = new ArrayList();
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getHoldings", userID);
+			
+			conn = getConn();
+            PreparedStatement stmt = getStatement(conn, getHoldingsForUserSQL);
+            stmt.setString(1, userID);
+
+			ResultSet rs = stmt.executeQuery();
+
+			while ( rs.next() )
+			{			
+				HoldingDataBean holdingData = getHoldingDataFromResultSet(rs);
+				holdingDataBeans.add(holdingData);
+			}
+
+			stmt.close();
+			commit(conn);
+				
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getHoldings -- error getting user holings", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return holdingDataBeans;
+	}
+
+	/**
+	 * @see TradeServices#getHolding(Integer)
+	 */
+	public HoldingDataBean getHolding(Integer holdingID) throws Exception {
+		HoldingDataBean holdingData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getHolding", holdingID);
+			
+			conn = getConn();
+			holdingData = getHoldingData(holdingID.intValue());
+
+			commit(conn);
+				
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getHolding -- error getting holding " + holdingID + "", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return holdingData;
+	}	
+
+	/**
+	 * @see TradeServices#getAccountData(String)
+	 */
+	public AccountDataBean getAccountData(String userID)
+	throws Exception
+	{
+		AccountDataBean accountData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getAccountData", userID);
+			
+			conn = getConn();
+			accountData = getAccountData(conn, userID);
+			commit(conn);
+				
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getAccountData -- error getting account data", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return accountData;		
+	}
+	private AccountDataBean getAccountData(Connection conn, String userID)
+	throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, getAccountForUserSQL);
+		stmt.setString(1, userID);
+		ResultSet rs = stmt.executeQuery();
+		AccountDataBean accountData = getAccountDataFromResultSet(rs);
+		stmt.close();
+		return accountData;         
+	}
+
+	private AccountDataBean getAccountDataForUpdate(Connection conn, String userID)
+	throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, getAccountForUserForUpdateSQL);
+		stmt.setString(1, userID);
+		ResultSet rs = stmt.executeQuery();
+		AccountDataBean accountData = getAccountDataFromResultSet(rs);
+		stmt.close();
+		return accountData;         
+	}
+	/**
+	 * @see TradeServices#getAccountData(String)
+	 */
+	public AccountDataBean getAccountData(int accountID)
+	throws Exception
+	{
+		AccountDataBean accountData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getAccountData", new Integer(accountID));
+			
+			conn = getConn();
+			accountData = getAccountData(accountID, conn);
+			commit(conn);
+				
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getAccountData -- error getting account data", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return accountData;		
+	}
+	private AccountDataBean getAccountData(int accountID, Connection conn)
+	throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, getAccountSQL);
+		stmt.setInt(1, accountID);
+		ResultSet rs = stmt.executeQuery();
+		AccountDataBean accountData = getAccountDataFromResultSet(rs);
+		stmt.close();
+		return accountData;         
+	}
+	private AccountDataBean getAccountDataForUpdate(int accountID, Connection conn)
+	throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, getAccountForUpdateSQL);
+		stmt.setInt(1, accountID);
+		ResultSet rs = stmt.executeQuery();
+		AccountDataBean accountData = getAccountDataFromResultSet(rs);
+		stmt.close();
+		return accountData;         
+	}	
+
+	private QuoteDataBean getQuoteData(String symbol)
+	throws Exception
+	{
+		QuoteDataBean quoteData = null;
+		Connection conn=null;
+		try
+		{
+			conn = getConn();
+			quoteData = getQuoteData(conn, symbol);
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getQuoteData -- error getting data", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return quoteData;		
+	}
+	private QuoteDataBean getQuoteData(Connection conn, String symbol)
+	throws Exception
+	{
+		QuoteDataBean quoteData = null;
+		PreparedStatement stmt = getStatement(conn, getQuoteSQL);
+		stmt.setString(1, symbol);
+		ResultSet rs = stmt.executeQuery();
+		if (!rs.next()) 
+			Log.error("TradeDirect:getQuoteData -- could not find quote for symbol="+symbol);
+		else
+			quoteData = getQuoteDataFromResultSet(rs);
+		stmt.close();
+		return quoteData;         
+	}
+	
+	private HoldingDataBean getHoldingData(int holdingID)
+	throws Exception
+	{
+		HoldingDataBean holdingData = null;
+		Connection conn=null;
+		try
+		{
+			conn = getConn();
+			holdingData = getHoldingData(conn, holdingID);
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getHoldingData -- error getting data", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return holdingData;		
+	}
+	private HoldingDataBean getHoldingData(Connection conn, int holdingID)
+	throws Exception
+	{
+		HoldingDataBean holdingData = null;
+		PreparedStatement stmt = getStatement(conn, getHoldingSQL);
+		stmt.setInt(1, holdingID);
+		ResultSet rs = stmt.executeQuery();
+		if (!rs.next()) 
+			Log.error("TradeDirect:getHoldingData -- no results -- holdingID="+holdingID);
+		else
+			holdingData = getHoldingDataFromResultSet(rs);
+
+		stmt.close();
+		return holdingData;         
+	}
+
+	private OrderDataBean getOrderData(int orderID)
+	throws Exception
+	{
+		OrderDataBean orderData = null;
+		Connection conn=null;
+		try
+		{
+			conn = getConn();
+			orderData = getOrderData(conn, orderID);
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getOrderData -- error getting data", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return orderData;		
+	}
+	private OrderDataBean getOrderData(Connection conn, int orderID)
+	throws Exception
+	{
+		OrderDataBean orderData = null;
+		if (Log.doTrace()) Log.trace("TradeDirect:getOrderData(conn, " + orderID + ")");		
+		PreparedStatement stmt = getStatement(conn, getOrderSQL);
+		stmt.setInt(1, orderID);
+		ResultSet rs = stmt.executeQuery();		
+		if (!rs.next())
+			Log.error("TradeDirect:getOrderData -- no results for orderID:" + orderID);	
+		else
+			orderData = getOrderDataFromResultSet(rs);
+		stmt.close();
+		return orderData;         
+	}
+
+	
+	/**
+	 * @see TradeServices#getAccountProfileData(String)
+	 */
+	public AccountProfileDataBean getAccountProfileData(String userID)
+	throws Exception
+	{
+		AccountProfileDataBean accountProfileData = null;
+		Connection conn=null;
+	
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getAccountProfileData", userID);
+			
+			conn = getConn();
+			accountProfileData = getAccountProfileData(conn, userID);
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getAccountProfileData -- error getting profile data", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return accountProfileData;		
+	}
+	private AccountProfileDataBean getAccountProfileData(Connection conn, String userID)
+	throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, getAccountProfileSQL);
+		stmt.setString(1, userID);
+
+		ResultSet rs = stmt.executeQuery();
+			
+		AccountProfileDataBean accountProfileData = getAccountProfileDataFromResultSet(rs);
+		stmt.close();
+		return accountProfileData;
+	}
+		
+
+	private AccountProfileDataBean getAccountProfileData(Integer accountID)
+	throws Exception
+	{
+		AccountProfileDataBean accountProfileData = null;
+		Connection conn=null;
+	
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:getAccountProfileData", accountID);
+			
+			conn = getConn();
+			accountProfileData = getAccountProfileData(conn, accountID);
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getAccountProfileData -- error getting profile data", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return accountProfileData;		
+	}
+	private AccountProfileDataBean getAccountProfileData(Connection conn, Integer accountID)
+	throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, getAccountProfileForAccountSQL);
+		stmt.setInt(1, accountID.intValue());
+
+		ResultSet rs = stmt.executeQuery();
+			
+		AccountProfileDataBean accountProfileData = getAccountProfileDataFromResultSet(rs);
+		stmt.close();
+		return accountProfileData;
+	}
+	
+
+	/**
+	 * @see TradeServices#updateAccountProfile(AccountProfileDataBean)
+	 */
+	public AccountProfileDataBean updateAccountProfile(AccountProfileDataBean profileData)
+	throws Exception {
+		AccountProfileDataBean accountProfileData = null;
+		Connection conn=null;
+	
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:updateAccountProfileData", profileData.getUserID());
+			
+			conn = getConn();
+			updateAccountProfile(conn, profileData);	
+
+			accountProfileData = getAccountProfileData(conn, profileData.getUserID());
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:getAccountProfileData -- error getting profile data", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return accountProfileData;		
+	}
+
+	private void creditAccountBalance(Connection conn, AccountDataBean accountData, BigDecimal credit)
+		throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, creditAccountBalanceSQL);
+
+		stmt.setBigDecimal(1, credit);
+		stmt.setInt(2, accountData.getAccountID().intValue());
+
+		int count = stmt.executeUpdate();
+		stmt.close();
+		
+	}
+
+
+    // Set Timestamp to zero to denote sell is inflight
+    // UPDATE  -- could add a "status" attribute to holding
+	private void updateHoldingStatus(Connection conn, Integer holdingID, String symbol)
+		throws Exception
+	{
+		Timestamp ts = new Timestamp(0);
+		PreparedStatement stmt = getStatement(conn, "update holdingejb set purchasedate= ? where holdingid = ?");
+
+		stmt.setTimestamp(1, ts);
+		stmt.setInt(2, holdingID.intValue());
+		int count = stmt.executeUpdate();
+		stmt.close();	
+	}
+
+	private void updateOrderStatus(Connection conn, Integer orderID, String status)
+		throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, updateOrderStatusSQL);
+
+		stmt.setString(1, status);
+		stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
+		stmt.setInt(3, orderID.intValue());
+		int count = stmt.executeUpdate();
+		stmt.close();	
+	}
+	
+	private void updateOrderHolding(Connection conn, int orderID, int holdingID)
+		throws Exception
+	{
+		PreparedStatement stmt = getStatement(conn, updateOrderHoldingSQL);
+
+		stmt.setInt(1, holdingID);
+		stmt.setInt(2, orderID);
+		int count = stmt.executeUpdate();
+		stmt.close();	
+	}
+	
+	private void updateAccountProfile(Connection conn, AccountProfileDataBean profileData)
+		throws Exception	
+	{
+		PreparedStatement stmt = getStatement(conn, updateAccountProfileSQL);
+
+		stmt.setString(1, profileData.getPassword());
+		stmt.setString(2, profileData.getFullName());
+		stmt.setString(3, profileData.getAddress());
+		stmt.setString(4, profileData.getEmail());
+		stmt.setString(5, profileData.getCreditCard());
+		stmt.setString(6, profileData.getUserID());                                                            
+
+		int count = stmt.executeUpdate();
+		stmt.close();
+	}
+	
+	private void updateQuoteVolume(Connection conn, QuoteDataBean quoteData, double quantity)
+		throws Exception	
+	{
+		PreparedStatement stmt = getStatement(conn, updateQuoteVolumeSQL);
+
+		stmt.setDouble(1, quantity);
+		stmt.setString(2, quoteData.getSymbol());
+
+		int count = stmt.executeUpdate();
+		stmt.close();	
+	}
+
+	public QuoteDataBean updateQuotePriceVolume(String symbol, BigDecimal changeFactor, double sharesTraded) throws Exception {
+		return updateQuotePriceVolumeInt(symbol, changeFactor, sharesTraded, publishQuotePriceChange);
+	}
+
+	/**
+	 * Update a quote's price and volume
+	 * @param symbol The PK of the quote
+	 * @param changeFactor the percent to change the old price by (between 50% and 150%)
+	 * @param sharedTraded the ammount to add to the current volume
+	 * @param publishQuotePriceChange used by the PingJDBCWrite Primitive to ensure no JMS is used, should
+	 *   be true for all normal calls to this API
+	 */
+	public QuoteDataBean updateQuotePriceVolumeInt(String symbol, BigDecimal changeFactor, double sharesTraded, boolean publishQuotePriceChange)
+		throws Exception	
+	{
+		
+		if ( TradeConfig.getUpdateQuotePrices() == false ) 
+			return new QuoteDataBean();	
+		
+		QuoteDataBean quoteData = null;
+		Connection conn=null;
+		UserTransaction txn = null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:updateQuotePriceVolume", symbol, changeFactor, new Double(sharesTraded));		
+
+			conn = getConn();
+
+			quoteData = getQuoteForUpdate(conn, symbol);		
+			BigDecimal oldPrice = quoteData.getPrice();
+			double newVolume = quoteData.getVolume() + sharesTraded;
+
+			if (oldPrice.equals(TradeConfig.PENNY_STOCK_PRICE)) {
+				changeFactor = TradeConfig.PENNY_STOCK_RECOVERY_MIRACLE_MULTIPLIER;
+			}
+
+			BigDecimal newPrice = changeFactor.multiply(oldPrice).setScale(2, BigDecimal.ROUND_HALF_UP);
+
+			updateQuotePriceVolume(conn, quoteData.getSymbol(), newPrice, newVolume);				
+			quoteData = getQuote(conn, symbol);
+
+			commit(conn);		
+
+			if (publishQuotePriceChange) {
+				publishQuotePriceChange(quoteData, oldPrice, changeFactor, sharesTraded);			
+			}
+			
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:updateQuotePriceVolume -- error updating quote price/volume for symbol:" + symbol);
+			rollBack(conn, e);
+			throw e;
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return quoteData;		
+	}
+
+	private void updateQuotePriceVolume(Connection conn, String symbol, BigDecimal newPrice, double newVolume)
+		throws Exception	
+	{		
+
+		PreparedStatement stmt = getStatement(conn, updateQuotePriceVolumeSQL);
+
+		stmt.setBigDecimal(1, newPrice);
+		stmt.setBigDecimal(2, newPrice);		
+		stmt.setDouble(3, newVolume);				
+		stmt.setString(4, symbol);
+
+		int count = stmt.executeUpdate();
+		stmt.close();	
+	}
+	private void publishQuotePriceChange(QuoteDataBean quoteData, BigDecimal oldPrice, BigDecimal changeFactor, double sharesTraded)
+	throws Exception
+	{
+		if (Log.doTrace())
+			Log.trace("TradeDirect:publishQuotePrice PUBLISHING to MDB quoteData = " + quoteData);		
+
+		javax.jms.Connection conn = null;	
+		Session sess = null;
+		
+		try
+		{
+			conn = tConnFactory.createConnection();		            					
+			sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
+			MessageProducer producer = sess.createProducer(streamerTopic);
+			TextMessage message = sess.createTextMessage();
+	
+			String command = "updateQuote";
+			message.setStringProperty("command", command);
+			message.setStringProperty("symbol",  quoteData.getSymbol() );
+			message.setStringProperty("company", quoteData.getCompanyName() );		
+			message.setStringProperty("price",   quoteData.getPrice().toString());
+			message.setStringProperty("oldPrice",oldPrice.toString());				
+			message.setStringProperty("open",    quoteData.getOpen().toString());
+			message.setStringProperty("low",     quoteData.getLow().toString());
+			message.setStringProperty("high",    quoteData.getHigh().toString());
+			message.setDoubleProperty("volume",  quoteData.getVolume());		
+					
+			message.setStringProperty("changeFactor", changeFactor.toString());		
+			message.setDoubleProperty("sharesTraded", sharesTraded);				
+			message.setLongProperty("publishTime", System.currentTimeMillis());					
+			message.setText("Update Stock price for " + quoteData.getSymbol() + " old price = " + oldPrice + " new price = " + quoteData.getPrice());
+
+			producer.send(message);
+		}
+		catch (Exception e)
+		{
+			throw e; //pass exception back
+			
+		}
+		
+		finally
+		{
+			if (conn != null)
+				conn.close();
+			if (sess != null)	
+				sess.close();					
+		}	
+	}		
+
+
+	/**
+	 * @see TradeServices#login(String, String)
+	 */
+	
+	public AccountDataBean login(String userID, String password)
+	throws Exception {
+
+		AccountDataBean accountData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.trace("TradeDirect:login", userID, password);
+			
+			conn = getConn();
+            PreparedStatement stmt = getStatement(conn, getAccountProfileSQL);
+            stmt.setString(1, userID);
+
+			ResultSet rs = stmt.executeQuery();
+			if ( !rs.next() )
+			{
+				Log.error("TradeDirect:login -- failure to find account for" + userID);
+				throw new javax.ejb.FinderException("Cannot find account for" + userID);
+			}
+				
+			String pw = rs.getString("password");
+			stmt.close();
+	    	if ( (pw==null) || (pw.equals(password) == false) )
+	    	{
+   	 			String error = "TradeDirect:Login failure for user: " + userID + 
+    						"\n\tIncorrect password-->" + userID + ":" + password;
+    			Log.error(error);
+ 		   		throw new Exception(error);
+	    	}
+	    	
+			stmt = getStatement(conn, loginSQL);
+			stmt.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
+            stmt.setString(2, userID);
+
+			int rows = stmt.executeUpdate();
+			//?assert rows==1?
+			
+			stmt = getStatement(conn, getAccountForUserSQL);
+			stmt.setString(1, userID);
+			rs = stmt.executeQuery();
+
+			accountData = getAccountDataFromResultSet(rs);
+			
+			stmt.close();
+		
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:login -- error logging in user", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return accountData;		
+
+		/*
+    	setLastLogin( new Timestamp(System.currentTimeMillis()) );
+    	setLoginCount( getLoginCount() + 1 );
+        */
+	}
+	
+	/**
+	 * @see TradeServices#logout(String)
+	 */
+	public void logout(String userID) throws Exception {
+		if (Log.doTrace()) Log.trace("TradeDirect:logout", userID);
+		Connection conn=null;
+		try
+		{		
+			conn = getConn();
+            PreparedStatement stmt = getStatement(conn, logoutSQL);
+            stmt.setString(1, userID);        
+			stmt.executeUpdate();
+			stmt.close();
+
+			commit(conn);
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:logout -- error logging out user", e);
+			rollBack(conn, e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+	}
+
+	/**
+	 * @see TradeServices#register(String, String, String, String, String, String, BigDecimal, boolean)
+	 */
+
+	public AccountDataBean register(
+		String userID,
+		String password,
+		String fullname,
+		String address,
+		String email,
+		String creditcard,
+		BigDecimal openBalance)
+		throws Exception {
+			
+		AccountDataBean accountData = null;
+		Connection conn=null;
+		try
+		{
+			if (Log.doTrace()) Log.traceEnter("TradeDirect:register");
+			
+			conn = getConn();
+            PreparedStatement stmt = getStatement(conn, createAccountSQL);
+
+			Integer accountID = KeySequenceDirect.getNextID(conn, "account", getInGlobalTxn());
+			BigDecimal balance = openBalance;
+			Timestamp creationDate = new Timestamp(System.currentTimeMillis());
+			Timestamp lastLogin  = creationDate;
+			int  loginCount = 0;
+			int  logoutCount = 0;
+			
+            stmt.setInt(1, accountID.intValue());			
+            stmt.setTimestamp(2, creationDate);
+            stmt.setBigDecimal(3, openBalance);
+            stmt.setBigDecimal(4, balance);  
+            stmt.setTimestamp(5, lastLogin);
+            stmt.setInt(6, loginCount);
+            stmt.setInt(7, logoutCount);
+            stmt.setString(8, userID);        
+			stmt.executeUpdate();
+			stmt.close();
+			
+            stmt = getStatement(conn, createAccountProfileSQL);
+			stmt.setString(1, userID);        
+			stmt.setString(2, password);        
+			stmt.setString(3, fullname);
+			stmt.setString(4, address);
+			stmt.setString(5, email);			
+			stmt.setString(6, creditcard);
+			stmt.executeUpdate();
+			stmt.close();
+									
+			commit(conn);
+				
+			accountData = new AccountDataBean(accountID, loginCount, logoutCount, lastLogin, creationDate, balance, openBalance, userID);
+			if (Log.doTrace()) Log.traceExit("TradeDirect:register");
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:register -- error registering new user", e);
+		}
+		finally
+		{
+			releaseConn(conn);
+		}
+		return accountData;
+	}
+
+	private AccountDataBean getAccountDataFromResultSet(ResultSet rs)
+	throws Exception
+	{
+		AccountDataBean accountData = null;
+
+
+		if (!rs.next() )
+			Log.error("TradeDirect:getAccountDataFromResultSet -- cannot find account data");
+				
+		else
+			accountData = new AccountDataBean(
+				new Integer(rs.getInt("accountID")),
+				rs.getInt("loginCount"),
+				rs.getInt("logoutCount"),
+				rs.getTimestamp("lastLogin"),
+				rs.getTimestamp("creationDate"),
+				rs.getBigDecimal("balance"),
+				rs.getBigDecimal("openBalance"),
+				rs.getString("profile_userID")			
+			);
+		return accountData;
+	}
+
+	private AccountProfileDataBean getAccountProfileDataFromResultSet(ResultSet rs)
+	throws Exception
+	{
+		AccountProfileDataBean accountProfileData = null;
+
+		if (!rs.next() )
+			Log.error("TradeDirect:getAccountProfileDataFromResultSet -- cannot find accountprofile data");
+		else			
+			accountProfileData = new AccountProfileDataBean(
+				rs.getString("userID"),
+				rs.getString("password"),
+				rs.getString("fullName"),
+				rs.getString("address"),
+				rs.getString("email"),
+				rs.getString("creditCard")
+			);
+			
+		return accountProfileData;
+	}
+
+	private HoldingDataBean getHoldingDataFromResultSet(ResultSet rs)
+	throws Exception
+	{
+		HoldingDataBean holdingData = null;
+
+		holdingData = new HoldingDataBean(
+			new Integer(rs.getInt("holdingID")),
+			rs.getDouble("quantity"),
+			rs.getBigDecimal("purchasePrice"),
+			rs.getTimestamp("purchaseDate"),
+			rs.getString("quote_symbol")
+		);
+		return holdingData;
+	}
+	
+	private QuoteDataBean getQuoteDataFromResultSet(ResultSet rs)
+	throws Exception
+	{
+		QuoteDataBean quoteData = null;
+
+		quoteData = new QuoteDataBean(
+			rs.getString("symbol"),
+			rs.getString("companyName"),
+			rs.getDouble("volume"),
+			rs.getBigDecimal("price"),
+			rs.getBigDecimal("open1"),
+			rs.getBigDecimal("low"),
+			rs.getBigDecimal("high"),
+			rs.getDouble("change1")
+		);
+		return quoteData;
+	}
+
+	private OrderDataBean getOrderDataFromResultSet(ResultSet rs)
+	throws Exception
+	{
+		OrderDataBean orderData = null;
+
+		orderData = new OrderDataBean(
+			new Integer(rs.getInt("orderID")),
+			rs.getString("orderType"),
+			rs.getString("orderStatus"),
+			rs.getTimestamp("openDate"),
+			rs.getTimestamp("completionDate"),
+			rs.getDouble("quantity"),
+			rs.getBigDecimal("price"),
+			rs.getBigDecimal("orderFee"),
+			rs.getString("quote_symbol")
+		);
+		return orderData;
+	}
+	
+
+	public RunStatsDataBean resetTrade(boolean deleteAll)
+	throws Exception
+	{
+		//Clear MDB Statistics		
+		MDBStats.getInstance().reset();
+		// Reset Trade		
+
+		RunStatsDataBean runStatsData = new RunStatsDataBean();
+		Connection conn=null;
+		UserTransaction txn = null;
+		try
+		{
+			if (Log.doTrace()) Log.traceEnter("TradeDirect: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,"TradeDirect: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");
+            int x = 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:%'");
+            int rowCount = 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:%')");
+            rowCount = 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:%')");
+            rowCount = stmt.executeUpdate();
+            stmt.close();
+            
+            stmt = getStatement(conn, "delete from accountejb where accountejb.accountid in (select accountid from accountejb a where a.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:%'");
+            rowCount = 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("TradeDirect: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("TradeDirect:releaseConn -- connection closed, connCount="+connCount);				
+				}
+			}
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:releaseConnection -- failed to close connection", e);
+		}
+	}
+
+   /*
+    * Lookup the TradeData datasource
+    *
+    */
+	private void getDataSource() throws Exception 
+	{
+		datasource = (DataSource) context.lookup(dsName);
+	}
+	
+
+   /*
+    * Allocate a new connection to the datasource
+    *
+    */
+    private static int connCount=0;
+    private static Integer lock = new Integer(0);
+	private Connection getConn() throws Exception 
+	{
+	
+		Connection conn = null;
+		if ( datasource == null )
+			getDataSource();
+		conn = datasource.getConnection();
+		conn.setAutoCommit(false);
+		if (Log.doTrace())
+		{
+			synchronized(lock)
+			{
+				connCount++;
+			}
+			Log.trace("TradeDirect:getConn -- new connection allocated, IsolationLevel=" + conn.getTransactionIsolation() + " connectionCount = " + connCount);
+		}
+
+		return conn;
+	}
+
+   /*
+    * Commit the provided connection if not under Global Transaction scope
+    * - conn.commit() is not allowed in a global transaction. the txn manager will
+    *	perform the commit
+    */	
+	private void commit(Connection conn)
+	throws Exception
+	{
+		if ( (getInGlobalTxn()==false) && (conn != null) )
+			conn.commit();
+	}
+	
+
+   /*
+    * Rollback the statement for the given connection
+    *
+    */
+   private void rollBack(Connection conn, Exception e) 
+   throws Exception 
+   {
+   		Log.log("TradeDirect:rollBack -- rolling back conn due to previously caught exception -- inGlobalTxn=" + getInGlobalTxn());
+		if ( (getInGlobalTxn()==false) && (conn != null) )
+	        conn.rollback();
+	    else
+	    	throw e;  // Throw the exception 
+	    			  // so the Global txn manager will rollBack
+   } 	
+	
+   /*
+    * Allocate a new prepared statment for this connection
+    *
+    */
+	private PreparedStatement getStatement(Connection conn, String sql) throws Exception {
+      return conn.prepareStatement(sql);
+	}
+	private PreparedStatement getStatement(Connection conn, String sql, int type, int concurrency) throws Exception {   
+      return conn.prepareStatement(sql, type, concurrency );
+	}
+	
+	
+	private static final String createQuoteSQL =
+		"insert into quoteejb " +
+		"( symbol, companyName, volume, price, open1, low, high, change1 ) " +
+		"VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  )";
+
+	private static final String createAccountSQL =
+		"insert into accountejb " +
+		"( accountID, creationDate, openBalance, balance, lastLogin, loginCount, logoutCount, profile_userid) " +
+		"VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  )";
+
+	private static final String createAccountProfileSQL =
+		"insert into accountprofileejb " +
+		"( userID, password, fullname, address, email, creditcard ) " +
+		"VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  )";
+
+	private static final String createHoldingSQL  = 
+		"insert into holdingejb " +
+		"( holdingID, purchaseDate, purchasePrice, quantity, quote_symbol, account_accountid ) " +
+		"VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ? )";
+
+	private static final String createOrderSQL = 
+		"insert into orderejb " +
+		"( orderid, ordertype, orderstatus, opendate, quantity, price, orderfee, account_accountid,  holding_holdingid, quote_symbol) " +
+		"VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  , ? , ? , ?)";
+
+	private static final String removeHoldingSQL  = 
+		"delete from holdingejb where holdingID = ?";
+
+	private static final String removeHoldingFromOrderSQL  = 		
+		"update orderejb set holding_holdingid=null where holding_holdingid = ?";
+	
+	private final static String updateAccountProfileSQL = 
+		"update accountprofileejb set " +
+		"password = ?, fullname = ?, address = ?, email = ?, creditcard = ? " +
+		"where userid = (select profile_userid from accountejb a " +
+		"where a.profile_userid=?)";
+
+	private final static String loginSQL=
+		"update accountejb set lastLogin=?, logincount=logincount+1 " +
+		"where profile_userID=?";
+
+	private static final String logoutSQL = 
+		"update accountejb set logoutcount=logoutcount+1 " +
+		"where profile_userid=?";
+	
+	private static final String getAccountSQL  = 
+		"select * from accountEJB a where a.accountid = ?";
+
+	private static final String getAccountForUpdateSQL  = 
+		"select * from accountEJB a where a.accountid = ? For Update";
+
+	private final static String getAccountProfileSQL = 
+		"select * from accountprofileejb ap where ap.userid = " + 
+		"(select profile_userid from accountejb a where a.profile_userid=?)";
+
+	private final static String getAccountProfileForAccountSQL = 
+		"select * from accountprofileejb ap where ap.userid = " + 
+		"(select profile_userid from accountejb a where a.accountID=?)";
+
+	private static final String getAccountForUserSQL  = 
+		"select * from accountEJB a where a.profile_userid = " +
+		"( select userid from accountprofileejb ap where ap.userid = ?)";
+
+	private static final String getAccountForUserForUpdateSQL  = 
+		"select * from accountEJB a where a.profile_userid = " +
+		"( select userid from accountprofileejb ap where ap.userid = ?) For Update";
+
+	private static final String getHoldingSQL  = 
+		"select * from holdingejb h where h.holdingid = ?";
+
+	private static final String getHoldingsForUserSQL  = 
+		"select * from holdingejb h where h.account_accountid = " +
+		"(select a.accountid from accountejb a where a.profile_userid = ?)";
+		
+	private static final String getOrderSQL  = 
+		"select * from orderejb o where o.orderid = ?";
+
+	private static final String getOrdersByUserSQL  = 
+		"select * from orderejb o where o.account_accountid = " +
+		"(select a.accountid from accountejb a where a.profile_userid = ?)";
+
+	private static final String getClosedOrdersSQL  = 
+		"select * from orderejb o " +
+		"where o.orderstatus = 'closed' AND o.account_accountid = " +
+		"(select a.accountid from accountejb a where a.profile_userid = ?)";
+
+	private static final String getQuoteSQL  = 
+		"select * from quoteejb q where q.symbol=?";
+
+	private static final String getAllQuotesSQL = 
+		"select * from quoteejb q";
+
+	private static final String getQuoteForUpdateSQL  = 
+		"select * from quoteejb q where q.symbol=? For Update";
+	
+	private static final String getTSIAQuotesOrderByChangeSQL  = 
+		"select * from quoteejb q " +
+		"where q.symbol like 's:1__' order by q.change1";
+
+	private static final String getTSIASQL  = 
+		"select SUM(price)/count(*) as TSIA from quoteejb q " +
+		"where q.symbol like 's:1__'";
+
+	private static final String getOpenTSIASQL  = 
+		"select SUM(open1)/count(*) as openTSIA from quoteejb q " +
+		"where q.symbol like 's:1__'";
+
+	private static final String getTSIATotalVolumeSQL =
+		"select SUM(volume) as totalVolume from quoteejb q " +
+		"where q.symbol like 's:1__'";		
+		
+	private static final String creditAccountBalanceSQL =
+		"update accountejb set " +
+		"balance = balance + ? " +
+		"where accountid = ?";
+
+	private static final String updateOrderStatusSQL =
+		"update orderejb set " +
+		"orderstatus = ?, completiondate = ? " +
+		"where orderid = ?";
+	
+	private static final String updateOrderHoldingSQL =
+		"update orderejb set " +
+		"holding_holdingID = ? " +
+		"where orderid = ?";	
+		
+	private static final String updateQuoteVolumeSQL =
+		"update quoteejb set " +
+		"volume = volume + ? " +
+		"where symbol = ?";
+
+	private static final String updateQuotePriceVolumeSQL =
+		"update quoteejb set " +
+		"price = ?, change1 = ? - open1, volume = ? " +
+		"where symbol = ?";
+		
+	
+
+
+	private static boolean initialized = false;
+	public static synchronized void init()	
+	{
+		TradeHome tradeHome=null;
+		if (initialized) return;
+		if (Log.doTrace())
+			Log.trace("TradeDirect:init -- *** initializing");		
+		try
+		{
+			if (Log.doTrace())
+				Log.trace("TradeDirect: init");			
+			context = new InitialContext();
+			datasource = (DataSource) context.lookup(dsName);			
+			
+			tradeHome = (TradeHome) ( javax.rmi.PortableRemoteObject.narrow(
+			context.lookup("java:comp/env/ejb/Trade"), TradeHome.class));
+			
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:init -- error on JNDI lookups of DataSource -- TradeDirect will not work", e);
+			return;
+		}			
+		try
+		{
+			qConnFactory = (ConnectionFactory) context.lookup("java:comp/env/jms/QueueConnectionFactory");
+			queue = (Queue) context.lookup("java:comp/env/jms/TradeBrokerQueue");
+			tConnFactory = (ConnectionFactory) context.lookup("java:comp/env/jms/TopicConnectionFactory");
+			streamerTopic = (Topic) context.lookup("java:comp/env/jms/TradeStreamerTopic");
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:init  Unable to lookup JMS Resources\n\t -- Asynchronous mode will not work correctly and Quote Price change publishing will be disabled",e);
+			publishQuotePriceChange = false;			
+		}		
+		try
+		{
+			tradeEJB = (Trade) tradeHome.create();					
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:init -- error looking up TradeEJB -- Asynchronous 1-phase will not work", e);
+		}					
+		if (Log.doTrace())		
+			Log.trace("TradeDirect:init -- +++ initialized");			
+		
+		initialized = true;		
+	}
+	public static void destroy()	
+	{
+		try
+		{
+			if (!initialized) return;
+			Log.trace("TradeDirect:destroy");
+		}
+		catch (Exception e)
+		{
+			Log.error("TradeDirect:destroy", e);
+		}
+	}
+
+
+	private static InitialContext context;
+	private static ConnectionFactory qConnFactory;
+	private static Queue queue;
+	private static ConnectionFactory tConnFactory;
+	private static Topic streamerTopic;
+	private static Trade tradeEJB;
+	private static boolean publishQuotePriceChange = true;
+	/**
+	 * Gets the inGlobalTxn
+	 * @return Returns a boolean
+	 */
+	private boolean getInGlobalTxn() {
+		return inGlobalTxn;
+	}
+	/**
+	 * Sets the inGlobalTxn
+	 * @param inGlobalTxn The inGlobalTxn to set
+	 */
+	private void setInGlobalTxn(boolean inGlobalTxn) {
+		this.inGlobalTxn = inGlobalTxn;
+	}
+
+}

Added: geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/AccountBean.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/AccountBean.java?rev=290479&view=auto
==============================================================================
--- geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/AccountBean.java (added)
+++ geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/AccountBean.java Tue Sep 20 09:07:08 2005
@@ -0,0 +1,230 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation or its licensors, as applicable 
+ *
+ *  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 org.apache.geronimo.samples.daytrader.ejb;
+
+import javax.ejb.*;
+import javax.naming.*;
+
+import org.apache.geronimo.samples.daytrader.util.*;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import org.apache.geronimo.samples.daytrader.*;
+
+public abstract class AccountBean
+		implements EntityBean {
+
+    private EntityContext context;
+    private LocalAccountProfileHome accountProfileHome;
+
+    /* Accessor methods for persistent fields */
+
+    public abstract Integer		getAccountID();				/* accountID */
+    public abstract void			setAccountID(Integer accountID);
+    public abstract int			getLoginCount();			/* loginCount */
+    public abstract void			setLoginCount(int loginCount);
+    public abstract int			getLogoutCount();			/* logoutCount */
+    public abstract void			setLogoutCount(int logoutCount);    
+    public abstract Timestamp		getLastLogin();				/* lastLogin Date */
+    public abstract void			setLastLogin(Timestamp lastLogin);        
+    public abstract Timestamp		getCreationDate();			/* creationDate */
+    public abstract void			setCreationDate(Timestamp creationDate);
+    public abstract BigDecimal	getBalance();				/* balance */
+    public abstract void			setBalance(BigDecimal balance);            
+    public abstract BigDecimal	getOpenBalance();			/* open balance */
+    public abstract void			setOpenBalance(BigDecimal openBalance);                
+    
+    /* Accessor methods for relationship fields */
+    public abstract LocalAccountProfile	getProfile();				/* This account's profile */
+    public abstract void				setProfile(LocalAccountProfile profile);    
+    public abstract Collection		getHoldings();				/* This account's holdings */
+    public abstract void				setHoldings(Collection holdings);    
+    public abstract Collection		getOrders();				/* This account's orders */
+    public abstract void				setOrders(Collection orders);    
+   
+    /* Select methods */
+
+    /* Business methods */
+    
+    public void login(String password)
+    {
+    	LocalAccountProfile profile = getProfile();
+    	if ( (profile==null) || (profile.getPassword().equals(password) == false) )
+    	{
+    		String error = "AccountBean:Login failure for account: " + getAccountID() + 
+    					( (profile==null)? "null AccountProfile" :
+    						"\n\tIncorrect password-->" + profile.getUserID() + ":" + profile.getPassword() );
+    		throw new EJBException(error);
+    	}
+    	
+    	setLastLogin( new Timestamp(System.currentTimeMillis()) );
+    	setLoginCount( getLoginCount() + 1 );
+	}
+	
+    public void logout()
+    {
+    	setLogoutCount( getLogoutCount() + 1 );
+	}
+
+	public AccountProfileDataBean updateAccountProfile(AccountProfileDataBean profileData)
+	throws FinderException
+	{
+		return getProfileForUpdate().updateAccountProfile(profileData);
+	}
+   	
+   	public AccountDataBean getDataBean()
+   	{
+   		return new AccountDataBean(getAccountID(),
+									getLoginCount(),
+									getLogoutCount(),
+									getLastLogin(),
+									getCreationDate(),
+									getBalance(),
+									getOpenBalance(),
+									(String)getProfile().getPrimaryKey());
+   	}    
+
+	public AccountProfileDataBean getProfileDataBean()
+	{
+		return getProfile().getDataBean();
+	}
+	public Collection getHoldingDataBeans()
+	{
+		Collection holdings = getHoldings();
+		ArrayList holdingDataBeans = new ArrayList(holdings.size());
+		Iterator it = holdings.iterator();
+		while (it.hasNext())
+		{
+			LocalHolding holding = (LocalHolding) it.next();
+			HoldingDataBean holdingData = holding.getDataBean();
+			holdingDataBeans.add(holdingData);
+		}
+		return holdingDataBeans;	
+	}
+
+	
+    /* Select methods */
+    public abstract Collection ejbSelectClosedOrders(Integer accountID)
+            throws FinderException;	
+                      
+	
+	public Collection getClosedOrders()
+			throws FinderException
+	{
+		return ejbSelectClosedOrders(getAccountID());
+	}
+	public LocalAccountProfile getProfileForUpdate()
+			throws FinderException
+	{
+		return getProfile();
+	}	
+	
+	public Collection getOrderDataBeans()
+	{
+		Collection orders = getOrders();
+		ArrayList orderDataBeans = new ArrayList(orders.size());
+		Iterator it = orders.iterator();
+		while (it.hasNext())
+		{
+			LocalOrder order = (LocalOrder) it.next();
+			OrderDataBean orderData = order.getDataBean();
+			orderDataBeans.add(orderData);
+		}
+		return orderDataBeans;
+	}
+	
+
	public String toString()
+	{
+		return getDataBean().toString();
+	}
+	
+	
+
+    /* Required javax.ejb.EntityBean interface methods */
+    public Integer ejbCreate (int accountID, String userID, String password, BigDecimal openBalance,
+            							String fullname, String address, String email, String creditcard)
+    throws CreateException {
+    	return ejbCreate(new Integer(accountID), userID, password, openBalance,
+    	        							fullname, address, email, creditcard);
+    }
+    
+    public Integer ejbCreate (Integer accountID, String userID, String password, BigDecimal openBalance, 
+            							String fullname, String address, String email, String creditCard)
+	throws CreateException {
+		
+        setAccountID(accountID);
+		setLoginCount(0);
+		setLogoutCount(0);
+		Timestamp current = new Timestamp(System.currentTimeMillis());
+        setLastLogin(current);
+        setCreationDate(current);
+		openBalance = openBalance.setScale(FinancialUtils.SCALE, FinancialUtils.ROUND);
+        setBalance (openBalance);
+        setOpenBalance (openBalance);
+	
+        return null;
+    }
+
+    public void ejbPostCreate (Integer accountID, String userID, String password, BigDecimal openBalance,
+        							String fullname, String address, String email, String creditCard)          
+	throws CreateException {
+		 //Account creates a new AccountProfile entity here.        
+		LocalAccountProfile profile = accountProfileHome.create(userID, password, fullname, address, email, creditCard);
+		setProfile(profile);
+	}
+	    
+    public void ejbPostCreate (int accountID, String userID, String password, BigDecimal openBalance,
+        							String fullname, String address, String email, String creditcard)
+	throws CreateException { 
+		ejbPostCreate(new Integer(accountID), userID, password, openBalance,fullname, address, email, creditcard);	
+	}
+
+    public void setEntityContext(EntityContext ctx) {
+        context = ctx;
+        try {
+			InitialContext ic = new InitialContext();
+			accountProfileHome = (LocalAccountProfileHome) ic.lookup("java:comp/env/ejb/AccountProfile");
+		}
+ 	    catch (NamingException ne)
+  	    {
+			Log.error(ne, "Account EJB: Lookup of Local Entity Homes Failed\n" + ne);
+		}
+  	}
+    
+    public void unsetEntityContext() {
+        context = null;
+    }
+    
+    public void ejbRemove() {
+    }
+    
+    public void ejbLoad() {
+    }
+    
+    public void ejbStore() {
+    }
+    
+    public void ejbPassivate() { 
+    }
+    
+    public void ejbActivate() { 
+    }
+}

Added: geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/AccountProfileBean.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/AccountProfileBean.java?rev=290479&view=auto
==============================================================================
--- geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/AccountProfileBean.java (added)
+++ geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/AccountProfileBean.java Tue Sep 20 09:07:08 2005
@@ -0,0 +1,131 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation or its licensors, as applicable 
+ *
+ *  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 org.apache.geronimo.samples.daytrader.ejb;
+
+import javax.ejb.*;
+import org.apache.geronimo.samples.daytrader.*;
+
+public abstract class AccountProfileBean
+		implements EntityBean {
+
+    private EntityContext context;
+
+    /* Accessor methods for persistent fields */
+
	public abstract String		getUserID();				/* userID */
+    public abstract void		setUserID(String userID);  
+    public abstract String		getPassword();				/* password */
+    public abstract void		setPassword(String password);
+    public abstract String		getFullName();				/* fullName */
+    public abstract void		setFullName(String fullName);  
+    public abstract String		getAddress();				/* address */
+    public abstract void		setAddress(String address);  
+    public abstract String		getEmail();					/* email */
+    public abstract void		setEmail(String email);  
+    public abstract String		getCreditCard();			/* creditCard */
+    public abstract void		setCreditCard(String creditCard);  
+ 
+    /* Accessor methods for relationship fields */
+    
+    //Account --> AccountProfile is a unidirectional relationship
+    // 		no relationship fields here
+    /* Accessor methods for relationship fields */
+    public abstract LocalAccount	getAccount();				/* This profile's account */
+    public abstract void				setAccount(LocalAccount account);    
+
+
+    /* Select methods */
+
+
+    /* Business methods */
+    public LocalAccount getAccountForUpdate() /* Get ths profile's account with a lock */
+    {
+    	 return getAccount();		
+    }
+    
+	public AccountProfileDataBean updateAccountProfile(AccountProfileDataBean profileData)
+	{
+		setPassword(profileData.getPassword());    
+		setFullName(profileData.getFullName());      
+		setAddress(profileData.getAddress());  
+		setEmail(profileData.getEmail());          
+		setCreditCard(profileData.getCreditCard());      
+		return getDataBean();
+	}   
+
+
+	public AccountProfileDataBean getDataBean()
+	{
+		return new AccountProfileDataBean(getUserID(),
+									getPassword(),
+									getFullName(),
+									getAddress(),
+									getEmail(),
+									getCreditCard());
+	}
+	
+	
+	public String toString()
+	{
+		return getDataBean().toString();
+	}
+
+
+    /* Required javax.ejb.EntityBean interface methods */
+    public String ejbCreate (String userID, String password, String fullname, 
+    							String address, String email, String creditcard)
+    throws CreateException {
+		
+        setUserID(userID);
+        setPassword(password);
+        setFullName(fullname);
+        setAddress(address);
+        setEmail(email);
+        setCreditCard(creditcard);
+        
+        return null;
+    }
+
+    public void ejbPostCreate (String userID, String password, String fullname, 
+    							String address, String email, String creditcard)
+
+	throws CreateException { }
+	    
+
+    public void setEntityContext(EntityContext ctx) {
+        context = ctx;
+    }
+    
+    public void unsetEntityContext() {
+        context = null;
+    }
+    
+    public void ejbRemove() {
+    }
+    
+    public void ejbLoad() {
+    }
+    
+    public void ejbStore() {
+    }
+    
+    public void ejbPassivate() { 
+    }
+    
+    public void ejbActivate() { 
+    }
+}

Added: geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/HoldingBean.java
URL: http://svn.apache.org/viewcvs/geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/HoldingBean.java?rev=290479&view=auto
==============================================================================
--- geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/HoldingBean.java (added)
+++ geronimo/trunk/sandbox/daytrader/modules/ejb/src/java/org/apache/geronimo/samples/daytrader/ejb/HoldingBean.java Tue Sep 20 09:07:08 2005
@@ -0,0 +1,128 @@
+/**
+ *
+ * Copyright 2005 The Apache Software Foundation or its licensors, as applicable 
+ *
+ *  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 org.apache.geronimo.samples.daytrader.ejb;
+
+import javax.ejb.*;
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import org.apache.geronimo.samples.daytrader.*;
+
+public abstract class HoldingBean
+		implements EntityBean {
+
+    private EntityContext context;
+
+    /* Accessor methods for persistent fields */
+
+    public abstract Integer		getHoldingID();				/* holdingID */
+    public abstract void		setHoldingID(Integer holdingID);
+    public abstract double		getQuantity();				/* quantity */
+    public abstract void		setQuantity(double quantity);    
+    public abstract BigDecimal	getPurchasePrice();			/* purchasePrice */
+    public abstract void		setPurchasePrice(BigDecimal purchasePrice);            
+    public abstract Timestamp	getPurchaseDate();			/* purchaseDate */
+    public abstract void		setPurchaseDate(Timestamp purchaseDate);               
+
+    /* Accessor methods for relationship fields */
+    public abstract LocalAccount	getAccount();			/* Account(1) <---> Holding(*) */
+    public abstract void			setAccount(LocalAccount account);    
+    public abstract LocalQuote		getQuote();				/* Holding(*)  ---> Quote(1) */
+    public abstract void			setQuote(LocalQuote quote);    
+
+    /* Select methods */
+ 
+   public abstract LocalQuote ejbSelectQuoteFromSymbol(String symbol)
+       throws FinderException;
+
+
+	private LocalQuote getQuoteFromSymbol(String symbol) throws FinderException 
+	{
+         LocalHolding holding = (LocalHolding) context.getEJBLocalObject();
+         return ejbSelectQuoteFromSymbol(symbol);
+	}
+
+    /* Business methods */
+    
+    public HoldingDataBean getDataBean()
+    {
+    	return new HoldingDataBean(getHoldingID(),
+									getQuantity(),
+									getPurchasePrice(),
+									getPurchaseDate(),
+									(String)getQuote().getPrimaryKey());
+    }
+
+	public String toString()
+	{
+		return getDataBean().toString();
+	}
+    
+
+    /* Required javax.ejb.EntityBean interface methods */
+    public Integer ejbCreate (int holdingID, LocalAccount account, LocalQuote quote, double quantity, BigDecimal purchasePrice) 
+    throws CreateException {
+    	return this.ejbCreate(new Integer(holdingID), account, quote, quantity, purchasePrice);
+    }
+
+    public Integer ejbCreate (Integer holdingID, LocalAccount account, LocalQuote quote, double quantity, BigDecimal purchasePrice) 
+	throws CreateException {
+
+        setHoldingID(holdingID);
+		setQuantity(quantity);
+		setPurchasePrice(purchasePrice);
+		setPurchaseDate(new Timestamp(System.currentTimeMillis()));
+
+        return null;
+    }
+
+    public void ejbPostCreate (Integer holdingID, LocalAccount account, LocalQuote quote, double quantity, BigDecimal purchasePrice)
+	throws CreateException { 
+		
+		//Establish relationship with Quote for this holding
+		setAccount(account);
+		setQuote(quote);
+	}
+	    
+    public void ejbPostCreate (int holdingID, LocalAccount account, LocalQuote quote, double quantity, BigDecimal purchasePrice)
+	throws CreateException { 
+	    	this.ejbPostCreate(new Integer(holdingID), account, quote, quantity, purchasePrice);
+	}
+
+    public void setEntityContext(EntityContext ctx) {
+        context = ctx;
+    }
+    
+    public void unsetEntityContext() {
+        context = null;
+    }
+    
+    public void ejbRemove() {
+    }
+    
+    public void ejbLoad() {
+    }
+    
+    public void ejbStore() {
+    }
+    
+    public void ejbPassivate() { 
+    }
+    
+    public void ejbActivate() { 
+    }
+}