001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    package org.apache.geronimo.samples.daytrader.direct;
018    
019    import java.math.BigDecimal;
020    import java.util.Collection;
021    import java.util.ArrayList;
022    import javax.naming.InitialContext;
023    import javax.transaction.UserTransaction;
024    import javax.jms.*;
025    
026    import javax.sql.DataSource;
027    
028    import org.apache.geronimo.samples.daytrader.ejb.Trade;
029    import org.apache.geronimo.samples.daytrader.ejb.TradeHome;
030    import org.apache.geronimo.samples.daytrader.util.*;
031    
032    import java.rmi.RemoteException;
033    import java.sql.Connection;
034    import java.sql.DatabaseMetaData;
035    import java.sql.PreparedStatement;
036    import java.sql.ResultSet;
037    import java.sql.SQLException;
038    import java.sql.Statement;
039    import java.sql.Timestamp;
040    
041    import org.apache.geronimo.samples.daytrader.*;;
042    
043    /**
044      * TradeDirect uses direct JDBC and JMS access to a <code>javax.sql.DataSource</code> to implement the business methods 
045      * of the Trade online broker application. These business methods represent the features and operations that 
046      * can be performed by customers of the brokerage such as login, logout, get a stock quote, buy or sell a stock, etc.
047      * and are specified in the {@link org.apache.geronimo.samples.daytrader.TradeServices} interface
048      *
049      * Note: In order for this class to be thread-safe, a new TradeJDBC must be created
050      * for each call to a method from the TradeInterface interface.  Otherwise, pooled
051      * connections may not be released.
052      *
053      * @see org.apache.geronimo.samples.daytrader.TradeServices
054      * @see org.apache.geronimo.samples.daytrader.ejb.Trade
055      *
056      */
057    
058    public class TradeDirect implements TradeServices
059                            
060    {
061            
062            private static String dsName = TradeConfig.DATASOURCE;
063            private static DataSource datasource = null;
064            private static BigDecimal ZERO = new BigDecimal(0.0);
065            private boolean inGlobalTxn = false;
066            private boolean inSession = false;
067    
068    
069            /**
070             * Zero arg constructor for TradeDirect
071             */
072            public TradeDirect() {
073                if (initialized==false) init();
074            }
075    
076            public TradeDirect(boolean inSession) {
077                    if (initialized == false)
078                            init();
079    
080                    this.inSession = inSession;
081            }
082    
083            /**
084             * @see TradeServices#getMarketSummary()
085             */
086            public MarketSummaryDataBean getMarketSummary() throws Exception {
087                    
088                    MarketSummaryDataBean marketSummaryData = null;
089                    Connection conn=null;
090                    try
091                    {
092                            if (Log.doTrace()) Log.trace("TradeDirect:getMarketSummary - inSession(" + this.inSession + ")");
093                            
094                            conn = getConn();
095                PreparedStatement stmt = getStatement(conn, getTSIAQuotesOrderByChangeSQL, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
096                
097                        ArrayList topGainersData = new ArrayList(5);
098                        ArrayList topLosersData = new ArrayList(5);             
099    
100                            ResultSet rs = stmt.executeQuery();
101                            
102                            int count = 0; 
103                            while (rs.next() && (count++ < 5) )
104                            {
105                                    QuoteDataBean quoteData = getQuoteDataFromResultSet(rs);
106                                    topLosersData.add(quoteData);
107                            }
108                            
109                            
110                            stmt.close();
111                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 );                  
112                            rs = stmt.executeQuery();
113    
114                            count = 0; 
115                            while (rs.next() && (count++ < 5) )
116                            {
117                                    QuoteDataBean quoteData = getQuoteDataFromResultSet(rs);
118                                    topGainersData.add(quoteData);
119                            }
120                                     
121                    
122                            /*
123                            rs.last();
124                            count = 0;
125                            while (rs.previous() && (count++ < 5) )
126                            {
127                                    QuoteDataBean quoteData = getQuoteDataFromResultSet(rs);
128                                    topGainersData.add(quoteData);
129                            }*/
130                            
131                            stmt.close();
132                            
133                BigDecimal TSIA = ZERO;
134                BigDecimal openTSIA = ZERO;
135                double volume=0.0;
136    
137                if ( (topGainersData.size() > 0) || (topLosersData.size() > 0)){ 
138                            
139                            stmt = getStatement(conn, getTSIASQL);
140                            rs = stmt.executeQuery();
141    
142                            if (!rs.next() )  
143                                    Log.error("TradeDirect:getMarketSummary -- error w/ getTSIASQL -- no results");
144                            else 
145                                    TSIA = rs.getBigDecimal("TSIA");
146                            stmt.close();
147    
148                            
149                            stmt = getStatement(conn, getOpenTSIASQL);
150                            rs = stmt.executeQuery();
151    
152                            if (!rs.next() )  
153                                    Log.error("TradeDirect:getMarketSummary -- error w/ getOpenTSIASQL -- no results");
154                            else 
155                                    openTSIA = rs.getBigDecimal("openTSIA");
156                            stmt.close();
157    
158                            stmt = getStatement(conn, getTSIATotalVolumeSQL);
159                            rs = stmt.executeQuery();
160    
161                            if (!rs.next() ) 
162                                    Log.error("TradeDirect:getMarketSummary -- error w/ getTSIATotalVolumeSQL -- no results");
163                            else 
164                                    volume = rs.getDouble("totalVolume");
165                            stmt.close();
166                }
167                            commit(conn);
168                                    
169                            marketSummaryData = new MarketSummaryDataBean(TSIA, openTSIA, volume, topGainersData, topLosersData);
170    
171                    }
172    
173                    catch (Exception e)
174                    {
175                            Log.error("TradeDirect:login -- error logging in user", e);
176                            rollBack(conn, e);
177                    }
178                    finally
179                    {
180                            releaseConn(conn);
181                    }
182                    return marketSummaryData;               
183    
184            }
185    
186            /**
187             * @see TradeServices#buy(String, String, double)
188             */
189            public OrderDataBean buy(String userID, String symbol, double quantity, int orderProcessingMode)
190                    throws Exception {
191    
192                    Connection conn=null;
193                    OrderDataBean orderData = null;
194                    UserTransaction txn = null;
195                    
196                    /*
197                     * total = (quantity * purchasePrice) + orderFee
198                     */
199                    BigDecimal total;
200                    
201            
202                    try
203                    {
204                            if (Log.doTrace()) 
205                                    Log.trace("TradeDirect:buy - inSession(" + this.inSession + ")", userID, symbol, new Double(quantity));
206                            
207                            if ( !inSession && orderProcessingMode == TradeConfig.ASYNCH_2PHASE )
208                            {
209                                    if ( Log.doTrace() )
210                                            Log.trace("TradeDirect:buy create/begin global transaction");           
211                                    //FUTURE the UserTransaction be looked up once
212                                    txn = (javax.transaction.UserTransaction) context.lookup("java:comp/UserTransaction");
213                                    txn.begin();
214                                    setInGlobalTxn(true);
215                            }
216                    
217                            conn = getConn();
218                            
219                            AccountDataBean accountData = getAccountData(conn, userID);
220                            QuoteDataBean quoteData = getQuoteData(conn, symbol);
221                            HoldingDataBean holdingData = null; // the buy operation will create the holding
222    
223                            orderData = createOrder(conn, accountData, quoteData, holdingData, "buy", quantity);
224    
225                            //Update -- account should be credited during completeOrder
226                            BigDecimal price = quoteData.getPrice();
227                            BigDecimal orderFee = orderData.getOrderFee();
228                            total   = (new BigDecimal(quantity).multiply(price)).add(orderFee);
229                            // subtract total from account balance
230                            creditAccountBalance(conn, accountData, total.negate());
231    
232                            try {
233                                    if (orderProcessingMode == TradeConfig.SYNCH) 
234                                            completeOrder(conn, orderData.getOrderID());
235                                    else if (orderProcessingMode == TradeConfig.ASYNCH)
236                                            queueOrder(orderData.getOrderID(), false);      // 1-phase commit
237                                    else //TradeConfig.ASYNC_2PHASE
238                                            queueOrder(orderData.getOrderID(), true);       // 2-phase commit
239                            }
240                            catch (JMSException je)
241                            {
242                                    Log.error("TradeBean:buy("+userID+","+symbol+","+quantity+") --> failed to queueOrder", je);
243                                    /* On exception - cancel the order */
244    
245                                    cancelOrder(conn, orderData.getOrderID());      
246                            }
247    
248                            orderData = getOrderData(conn, orderData.getOrderID().intValue());
249                            
250                            if (txn != null) {
251                                    if ( Log.doTrace() )
252                                            Log.trace("TradeDirect:buy committing global transaction");             
253                                    txn.commit();
254                                    setInGlobalTxn(false);
255                            }
256                            else
257                                    commit(conn);
258                    }
259                    catch (Exception e)
260                    {
261                            Log.error("TradeDirect:buy error - rolling back", e);
262                            if ( getInGlobalTxn() )
263                                    txn.rollback();
264                            else
265                                    rollBack(conn, e);
266                    }
267                    finally
268                    {
269                            releaseConn(conn);
270                    }
271    
272                    return orderData;               
273            }
274    
275            /**
276             * @see TradeServices#sell(String, Integer)
277             */
278            public OrderDataBean sell(String userID, Integer holdingID, int orderProcessingMode)
279                    throws Exception {
280                    Connection conn=null;
281                    OrderDataBean orderData = null;
282                    UserTransaction txn = null;
283                    
284                    /*
285                     * total = (quantity * purchasePrice) + orderFee
286                     */
287                    BigDecimal total;
288                    
289                    try
290                    {
291                            if (Log.doTrace()) 
292                                    Log.trace("TradeDirect:sell - inSession(" + this.inSession + ")", userID, holdingID);
293    
294                            if ( !inSession && orderProcessingMode == TradeConfig.ASYNCH_2PHASE )
295                            {
296                                    if ( Log.doTrace() )
297                                            Log.trace("TradeDirect:sell create/begin global transaction");          
298                                    //FUTURE the UserTransaction be looked up once
299    
300                                    txn = (javax.transaction.UserTransaction) context.lookup("java:comp/UserTransaction");
301                                    txn.begin();
302                                    setInGlobalTxn(true);
303                            }
304                            
305                            conn = getConn();
306                            
307                            AccountDataBean accountData = getAccountData(conn, userID);
308                            HoldingDataBean holdingData = getHoldingData(conn, holdingID.intValue() );
309                            QuoteDataBean quoteData = null;
310                            if ( holdingData != null) quoteData = getQuoteData(conn, holdingData.getQuoteID());
311                            
312                            if ( (accountData==null) || (holdingData==null) || (quoteData==null) )
313                            {
314                                    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;
315                                    Log.error(error);
316                                    if ( getInGlobalTxn() )
317                                            txn.rollback();
318                                    else
319                                            rollBack(conn, new Exception(error));                                                   
320                                    return orderData;
321                            }
322    
323                            double           quantity = holdingData.getQuantity();
324    
325                            orderData = createOrder(conn, accountData, quoteData, holdingData, "sell", quantity);
326                            
327                            // Set the holdingSymbol purchaseDate to selling to signify the sell is "inflight"
328                            updateHoldingStatus(conn, holdingData.getHoldingID(), holdingData.getQuoteID());                
329    
330                            //UPDATE -- account should be credited during completeOrder
331                            BigDecimal price = quoteData.getPrice();
332                            BigDecimal orderFee = orderData.getOrderFee();
333                            total   = (new BigDecimal(quantity).multiply(price)).subtract(orderFee);
334                            creditAccountBalance(conn, accountData, total);
335    
336                            try {
337                                    if (orderProcessingMode == TradeConfig.SYNCH) 
338                                            completeOrder(conn, orderData.getOrderID());
339                                    else if (orderProcessingMode == TradeConfig.ASYNCH)
340                                            queueOrder(orderData.getOrderID(), false);  // 1-phase commit
341                                    else //TradeConfig.ASYNC_2PHASE
342                                            queueOrder(orderData.getOrderID(), true);      // 2-phase commit
343                            }
344                            catch (JMSException je)
345                            {
346                                    Log.error("TradeBean:sell("+userID+","+holdingID+") --> failed to queueOrder", je);
347                                    /* On exception - cancel the order */
348    
349                                    cancelOrder(conn, orderData.getOrderID());      
350                            }
351    
352                            orderData = getOrderData(conn, orderData.getOrderID().intValue());
353    
354                            if (txn != null) {
355                                    if ( Log.doTrace() )
356                                            Log.trace("TradeDirect:sell committing global transaction");            
357                                    txn.commit();
358                                    setInGlobalTxn(false);
359                            }
360                            else    
361                                    commit(conn);                   
362                    }
363                    catch (Exception e)
364                    {
365                            Log.error("TradeDirect:sell error", e);
366                            if ( getInGlobalTxn() )
367                                    txn.rollback();
368                            else
369                                    rollBack(conn, e);
370                    }
371                    finally
372                    {
373                            releaseConn(conn);
374                    }
375                    
376                    return orderData;               
377            }
378    
379            /**
380             * @see TradeServices#queueOrder(Integer)
381             */
382            public void queueOrder(Integer orderID, boolean twoPhase) throws Exception 
383            {
384                    if (Log.doTrace() ) Log.trace("TradeDirect:queueOrder - inSession(" + this.inSession + ")", orderID);
385    
386                    javax.jms.Connection conn = null;       
387                    Session sess = null;
388            
389                    try 
390                    {       
391                            conn = qConnFactory.createConnection();         
392                            sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
393                            MessageProducer producer = sess.createProducer(queue);
394    
395                            TextMessage   message = sess.createTextMessage();
396    
397                            String command= "neworder";
398                            message.setStringProperty("command", command);
399                            message.setIntProperty("orderID", orderID.intValue());
400                            message.setBooleanProperty("twoPhase", twoPhase);
401                            message.setBooleanProperty("direct", true);
402                            message.setLongProperty("publishTime", System.currentTimeMillis());                                     
403                            message.setText("neworder: orderID="+orderID + " runtimeMode=Direct twoPhase="+twoPhase);
404    
405                            if (Log.doTrace()) 
406                                    Log.trace("TradeDirectBean:queueOrder Sending message: " + message.getText());
407                            producer.send(message);
408                            sess.close();
409                    }
410                    
411                    catch (Exception e)
412                    {
413                            throw e; // pass the exception back
414                    }
415                    
416                    finally
417                    {
418                            if (sess != null)
419                                    sess.close();
420                    }
421            }
422    
423    
424            /**
425             * @see TradeServices#completeOrder(Integer)
426             */
427            public OrderDataBean completeOrder(Integer orderID, boolean twoPhase) throws Exception 
428            {
429                    OrderDataBean orderData = null;
430                    Connection conn=null;
431    
432                    if (!twoPhase)
433                    {
434                            if (Log.doTrace())
435                                    Log.trace("TradeDirect:completeOrder -- completing order in 1-phase, calling tradeEJB to start new txn. orderID="+orderID);
436                            return tradeEJB.completeOrderOnePhaseDirect(orderID);
437                    }               
438                    try  //twoPhase
439                    {
440    
441                            if (Log.doTrace()) Log.trace("TradeDirect:completeOrder - inSession(" + this.inSession + ")", orderID);
442                            setInGlobalTxn(!inSession && twoPhase);
443                            conn = getConn();
444                            orderData = completeOrder(conn, orderID);
445                            commit(conn);
446    
447                    }
448                    catch (Exception e)
449                    {
450                            Log.error("TradeDirect:completeOrder -- error completing order", e);
451                            rollBack(conn, e);
452                            cancelOrder(orderID, twoPhase);
453                    }
454                    finally
455                    {
456                            releaseConn(conn);
457                    }
458                            
459                    return orderData;               
460                    
461            }
462            public OrderDataBean completeOrderOnePhase(Integer orderID) throws Exception 
463            {
464                    OrderDataBean orderData = null;
465                    Connection conn=null;
466                    try
467                    {
468                            if (Log.doTrace()) Log.trace("TradeDirect:completeOrderOnePhase - inSession(" + this.inSession + ")", orderID);
469                            setInGlobalTxn(false);
470                            conn = getConn();
471                            orderData = completeOrder(conn, orderID);
472    
473                            commit(conn);
474    
475                    }
476                    catch (Exception e)
477                    {
478                            Log.error("TradeDirect:completeOrderOnePhase -- error completing order", e);
479                            rollBack(conn, e);
480                            cancelOrder(orderID, false);
481                    }
482                    finally
483                    {
484                            releaseConn(conn);
485                    }
486                                    
487                    return orderData;               
488                    
489            }
490    
491            private OrderDataBean completeOrder(Connection conn, Integer orderID) 
492                            throws Exception
493            {
494                            
495                    OrderDataBean orderData = null;
496                    if (Log.doTrace()) Log.trace("TradeDirect:completeOrderInternal - inSession(" + this.inSession + ")", orderID);
497    
498                    PreparedStatement stmt = getStatement(conn, getOrderSQL);
499            stmt.setInt(1, orderID.intValue());
500    
501                    ResultSet rs = stmt.executeQuery();
502    
503                    if ( !rs.next() )
504                    {
505                            Log.error("TradeDirect:completeOrder -- unable to find order: " + orderID);
506                            stmt.close();
507                            return orderData;
508                    }
509                    orderData = getOrderDataFromResultSet(rs);
510                    
511                    String orderType = orderData.getOrderType();
512                    String orderStatus = orderData.getOrderStatus();
513                    
514                    //if (order.isCompleted())
515            if ( (orderStatus.compareToIgnoreCase("completed") == 0) ||
516                     (orderStatus.compareToIgnoreCase("alertcompleted") == 0)    ||
517                     (orderStatus.compareToIgnoreCase("cancelled") == 0) )           
518                            throw new Exception("TradeDirect:completeOrder -- attempt to complete Order that is already completed");
519            
520                    int        accountID = rs.getInt("account_accountID");
521                    String       quoteID = rs.getString("quote_symbol");
522                    int        holdingID = rs.getInt("holding_holdingID");
523                    
524                    BigDecimal     price = orderData.getPrice();
525                    double      quantity = orderData.getQuantity();
526                    BigDecimal  orderFee = orderData.getOrderFee();
527    
528                    //get the data for the account and quote 
529                    //the holding will be created for a buy or extracted for a sell
530    
531    
532                    /* Use the AccountID and Quote Symbol from the Order
533                            AccountDataBean accountData = getAccountData(accountID, conn);
534                            QuoteDataBean     quoteData = getQuoteData(conn, quoteID);
535                     */
536                    String                           userID = getAccountProfileData(conn, new Integer(accountID)).getUserID();
537    
538                    HoldingDataBean holdingData = null;
539                    
540                    if (Log.doTrace()) Log.trace(
541                                    "TradeDirect:completeOrder--> Completing Order " + orderData.getOrderID()
542                                     + "\n\t Order info: "   +   orderData
543                                     + "\n\t Account info: " + accountID
544                                     + "\n\t Quote info: "   +   quoteID);
545    
546                    //if (order.isBuy())
547                    if ( orderType.compareToIgnoreCase("buy") == 0 )
548                    { 
549                            /* Complete a Buy operation
550                             *      - create a new Holding for the Account
551                             *      - deduct the Order cost from the Account balance
552                             */
553            
554                            holdingData = createHolding(conn, accountID, quoteID, quantity, price);
555                            updateOrderHolding(conn, orderID.intValue(), holdingData.getHoldingID().intValue());
556                    }
557                    
558                    //if (order.isSell()) {
559                    if ( orderType.compareToIgnoreCase("sell") == 0 ) 
560                    {       
561                            /* Complete a Sell operation
562                             *      - remove the Holding from the Account
563                             *      - deposit the Order proceeds to the Account balance
564                             */     
565                            holdingData = getHoldingData(conn, holdingID);
566                            if ( holdingData == null )
567                                    Log.debug("TradeDirect:completeOrder:sell -- user: " + userID + " already sold holding: " + holdingID);                 
568                            else
569                                    removeHolding(conn, holdingID, orderID.intValue());             
570    
571                    }
572    
573                    updateOrderStatus(conn, orderData.getOrderID(), "closed");
574                    
575                    if (Log.doTrace()) Log.trace(
576                            "TradeDirect:completeOrder--> Completed Order " + orderData.getOrderID()
577                                     + "\n\t Order info: "   +   orderData
578                                     + "\n\t Account info: " + accountID
579                                     + "\n\t Quote info: "   +   quoteID
580                                     + "\n\t Holding info: " + holdingData);
581    
582                    stmt.close();
583    
584                    commit(conn);
585    
586                    //signify this order for user userID is complete                
587                    TradeAction tradeAction = new TradeAction(this);                
588                    tradeAction.orderCompleted(userID, orderID);
589    
590                    return orderData;
591            }
592            
593            /**
594             * @see TradeServices#cancelOrder(Integer, boolean)
595             */
596            public void cancelOrder(Integer orderID, boolean twoPhase) 
597            throws Exception 
598            {
599                    OrderDataBean orderData = null;
600                    Connection conn=null;
601                    try
602                    {
603                            if (Log.doTrace()) Log.trace("TradeDirect:cancelOrder - inSession(" + this.inSession + ")", orderID);
604                            setInGlobalTxn(!inSession && twoPhase);
605                            conn = getConn();
606                            cancelOrder(conn, orderID);
607                            commit(conn);
608    
609                    }
610                    catch (Exception e)
611                    {
612                            Log.error("TradeDirect:cancelOrder -- error cancelling order: "+orderID, e);
613                            rollBack(conn, e);
614                    }
615                    finally
616                    {
617                            releaseConn(conn);
618                    }               
619            }
620            public void cancelOrderOnePhase(Integer orderID) 
621            throws Exception 
622            {
623                    OrderDataBean orderData = null;
624                    Connection conn=null;
625                    try
626                    {
627                            if (Log.doTrace()) Log.trace("TradeDirect:cancelOrderOnePhase - inSession(" + this.inSession + ")", orderID);
628                            setInGlobalTxn(false);
629                            conn = getConn();
630                            cancelOrder(conn, orderID);
631                            commit(conn);
632    
633                    }
634                    catch (Exception e)
635                    {
636                            Log.error("TradeDirect:cancelOrderOnePhase -- error cancelling order: "+orderID, e);
637                            rollBack(conn, e);
638                    }
639                    finally
640                    {
641                            releaseConn(conn);
642                    }               
643            }       
644            private void cancelOrder(Connection conn, Integer orderID) 
645            throws Exception 
646            {
647                    updateOrderStatus(conn, orderID, "cancelled");
648            }
649            
650    
651            public void orderCompleted(String userID, Integer orderID) 
652            throws Exception
653            {
654                    throw new UnsupportedOperationException("TradeDirect:orderCompleted method not supported");
655            }
656            
657    
658            private HoldingDataBean createHolding(Connection conn, int accountID, String symbol, double quantity, BigDecimal purchasePrice) 
659                    throws Exception 
660            {
661                    HoldingDataBean holdingData = null;
662    
663                    Timestamp purchaseDate = new Timestamp(System.currentTimeMillis());
664                    PreparedStatement stmt = getStatement(conn, createHoldingSQL);
665            
666                    Integer holdingID = KeySequenceDirect.getNextID(conn, "holding", inSession, getInGlobalTxn());
667                    stmt.setInt(1, holdingID.intValue());
668                    stmt.setTimestamp(2, purchaseDate);
669                    stmt.setBigDecimal(3, purchasePrice);
670                    stmt.setDouble(4, quantity);
671                    stmt.setString(5, symbol);
672                    stmt.setInt(6, accountID);
673                    int rowCount = stmt.executeUpdate();
674    
675                    stmt.close();
676                                    
677                    return getHoldingData(conn, holdingID.intValue());
678            }
679            private void removeHolding(Connection conn, int holdingID, int orderID) 
680                    throws Exception 
681            {
682                    PreparedStatement stmt = getStatement(conn, removeHoldingSQL);
683            
684                    stmt.setInt(1, holdingID);
685                    int rowCount = stmt.executeUpdate();
686                    stmt.close();   
687    
688                    // set the HoldingID to NULL for the purchase and sell order now that
689                    // the holding as been removed          
690                    stmt = getStatement(conn, removeHoldingFromOrderSQL);
691            
692                    stmt.setInt(1, holdingID);
693                    rowCount = stmt.executeUpdate();
694                    stmt.close();   
695                    
696            }
697            
698            private OrderDataBean createOrder(Connection conn, AccountDataBean accountData, QuoteDataBean quoteData, HoldingDataBean holdingData, String orderType, double quantity) 
699                    throws Exception 
700            {
701                    OrderDataBean orderData = null;
702    
703                    Timestamp currentDate = new Timestamp(System.currentTimeMillis());
704                                    
705                    PreparedStatement stmt = getStatement(conn, createOrderSQL);
706            
707    
708                    Integer orderID = KeySequenceDirect.getNextID(conn, "order", inSession, getInGlobalTxn());
709                    stmt.setInt(1, orderID.intValue());
710                    stmt.setString(2, orderType);
711                    stmt.setString(3, "open");
712                    stmt.setTimestamp(4, currentDate);
713                    stmt.setDouble(5, quantity);
714                    stmt.setBigDecimal(6, quoteData.getPrice().setScale(FinancialUtils.SCALE, FinancialUtils.ROUND));
715                    stmt.setBigDecimal(7, TradeConfig.getOrderFee(orderType));
716                    stmt.setInt(8, accountData.getAccountID().intValue());
717                    if (holdingData == null ) stmt.setNull(9, java.sql.Types.INTEGER);
718                    else stmt.setInt(9, holdingData.getHoldingID().intValue());
719                    stmt.setString(10, quoteData.getSymbol());              
720                    int rowCount = stmt.executeUpdate();
721    
722                    stmt.close();
723                                    
724                    return getOrderData(conn, orderID.intValue());
725            }
726            
727    
728            /**
729             * @see TradeServices#getOrders(String)
730             */
731            public Collection getOrders(String userID) throws Exception {
732                    Collection orderDataBeans = new ArrayList();
733                    Connection conn=null;
734                    try
735                    {
736                            if (Log.doTrace()) Log.trace("TradeDirect:getOrders - inSession(" + this.inSession + ")", userID);
737                            
738                            conn = getConn();
739                PreparedStatement stmt = getStatement(conn, getOrdersByUserSQL);
740                stmt.setString(1, userID);
741    
742                            ResultSet rs = stmt.executeQuery();
743    
744                            //TODO: return top 5 orders for now -- next version will add a getAllOrders method
745                            //      also need to get orders sorted by order id descending                   
746                            int i=0;
747                            while ( (rs.next()) && (i++ < 5) )
748                            {                       
749                                    OrderDataBean orderData = getOrderDataFromResultSet(rs);
750                                    orderDataBeans.add(orderData);
751                            }
752    
753                            stmt.close();
754                            commit(conn);
755                                    
756                    }
757                    catch (Exception e)
758                    {
759                            Log.error("TradeDirect:getOrders -- error getting user orders", e);
760                            rollBack(conn, e);
761                    }
762                    finally
763                    {
764                            releaseConn(conn);
765                    }
766                    return orderDataBeans;
767            }
768    
769            /**
770             * @see TradeServices#getClosedOrders(String)
771             */
772            public Collection getClosedOrders(String userID) throws Exception {
773                    Collection orderDataBeans = new ArrayList();
774                    Connection conn=null;
775                    try
776                    {
777                            if (Log.doTrace()) Log.trace("TradeDirect:getClosedOrders - inSession(" + this.inSession + ")", userID);
778                            
779                            conn = getConn();
780                PreparedStatement stmt = getStatement(conn, getClosedOrdersSQL);
781                stmt.setString(1, userID);
782    
783                            ResultSet rs = stmt.executeQuery();
784    
785                            while ( rs.next() )
786                            {                       
787                                    OrderDataBean orderData = getOrderDataFromResultSet(rs);        
788                                    orderData.setOrderStatus("completed");
789                                    updateOrderStatus(conn, orderData.getOrderID(), orderData.getOrderStatus());
790                                    orderDataBeans.add(orderData);
791                                    
792                            }
793    
794                            stmt.close();
795                            commit(conn);
796                    }
797                    catch (Exception e)
798                    {
799                            Log.error("TradeDirect:getOrders -- error getting user orders", e);
800                            rollBack(conn, e);
801                    }
802                    finally
803                    {
804                            releaseConn(conn);
805                    }
806                    return orderDataBeans;
807            }
808    
809            /**
810             * @see TradeServices#createQuote(String, String, BigDecimal)
811             */
812            public QuoteDataBean createQuote(
813                    String symbol,
814                    String companyName,
815                    BigDecimal price)
816                    throws Exception {
817                    
818                    QuoteDataBean quoteData = null;
819                    Connection conn=null;
820                    try
821                    {
822                            if (Log.doTrace()) Log.traceEnter("TradeDirect:createQuote - inSession(" + this.inSession + ")");
823                            
824                            price = price.setScale(FinancialUtils.SCALE, FinancialUtils.ROUND);
825                            double volume=0.0, change=0.0;
826    
827                            conn = getConn();
828                PreparedStatement stmt = getStatement(conn, createQuoteSQL);
829                stmt.setString(1, symbol);                  // symbol
830                stmt.setString(2, companyName);             // companyName
831                stmt.setDouble(3, volume);                  // volume
832                stmt.setBigDecimal(4, price);               // price
833                stmt.setBigDecimal(5, price);               // open
834                stmt.setBigDecimal(6, price);               // low
835                stmt.setBigDecimal(7, price);               // high
836                stmt.setDouble(8, change);                  // change
837    
838                            stmt.executeUpdate();
839                            stmt.close();
840                            commit(conn);
841                                    
842                            quoteData = new QuoteDataBean(symbol, companyName, volume, price, price, price, price, change);
843                            if (Log.doTrace()) Log.traceExit("TradeDirect:createQuote");
844                    }
845                    catch (Exception e)
846                    {
847                            Log.error("TradeDirect:createQuote -- error creating quote", e);
848                    }
849                    finally
850                    {
851                            releaseConn(conn);
852                    }
853                    return quoteData;
854            }
855            
856            /**
857             * @see TradeServices#getQuote(String)
858             */
859            
860            public QuoteDataBean getQuote(String symbol) throws Exception {
861                    QuoteDataBean quoteData = null;
862                    Connection conn=null;
863                    UserTransaction txn = null;
864                    try
865                    {
866                            if (Log.doTrace()) Log.trace("TradeDirect:getQuote - inSession(" + this.inSession + ")", symbol);
867    
868                            conn = getConn();
869                            quoteData = getQuote(conn, symbol);                     
870                            commit(conn);                   
871                    }
872                    catch (Exception e)
873                    {
874                            Log.error("TradeDirect:getQuote -- error getting quote", e);
875                            rollBack(conn, e);
876                    }
877                    finally
878                    {
879                            releaseConn(conn);
880                    }
881                    return quoteData;               
882            }
883            
884            private QuoteDataBean getQuote(Connection conn, String symbol) 
885            throws Exception 
886            {
887                    QuoteDataBean quoteData = null;
888                    PreparedStatement stmt = getStatement(conn, getQuoteSQL);
889                    stmt.setString(1, symbol);                      // symbol
890            
891                    ResultSet rs = stmt.executeQuery();
892                                            
893                    if ( !rs.next() )
894                            Log.error("TradeDirect:getQuote -- failure no result.next() for symbol: " + symbol);
895                                    
896                    else
897                            quoteData = getQuoteDataFromResultSet(rs);
898    
899                    stmt.close();
900                    
901                    return quoteData;
902            }
903    
904            private QuoteDataBean getQuoteForUpdate(Connection conn, String symbol) 
905            throws Exception 
906            {
907                    QuoteDataBean quoteData = null;
908                    PreparedStatement stmt = getStatement(conn, getQuoteForUpdateSQL);
909                    stmt.setString(1, symbol);                      // symbol
910            
911                    ResultSet rs = stmt.executeQuery();
912                                            
913                    if ( !rs.next() )
914                            Log.error("TradeDirect:getQuote -- failure no result.next()");
915                                    
916                    else
917                            quoteData = getQuoteDataFromResultSet(rs);
918    
919                    stmt.close();
920                    
921                    return quoteData;
922            }       
923            
924            /**
925             * @see TradeServices#getAllQuotes(String)
926             */
927            public Collection getAllQuotes() throws Exception {
928                    Collection quotes = new ArrayList();
929                    QuoteDataBean quoteData = null;
930    
931                    Connection conn = null;
932                    try {
933                            conn = getConn();
934    
935                            PreparedStatement stmt = getStatement(conn, getAllQuotesSQL);
936            
937                            ResultSet rs = stmt.executeQuery();
938    
939                            while (!rs.next()) {
940                                    quoteData = getQuoteDataFromResultSet(rs);
941                                    quotes.add(quoteData);
942                            }
943    
944                            stmt.close();
945                    }
946                    catch (Exception e) {
947                            Log.error("TradeDirect:getAllQuotes", e);
948                            rollBack(conn, e);
949                    }
950                    finally {
951                            releaseConn(conn);
952                    }
953                    
954                    return quotes;
955            }
956    
957            /**
958             * @see TradeServices#getHoldings(String)
959             */
960            public Collection getHoldings(String userID) throws Exception {
961                    Collection holdingDataBeans = new ArrayList();
962                    Connection conn=null;
963                    try
964                    {
965                            if (Log.doTrace()) Log.trace("TradeDirect:getHoldings - inSession(" + this.inSession + ")", userID);
966                            
967                            conn = getConn();
968                PreparedStatement stmt = getStatement(conn, getHoldingsForUserSQL);
969                stmt.setString(1, userID);
970    
971                            ResultSet rs = stmt.executeQuery();
972    
973                            while ( rs.next() )
974                            {                       
975                                    HoldingDataBean holdingData = getHoldingDataFromResultSet(rs);
976                                    holdingDataBeans.add(holdingData);
977                            }
978    
979                            stmt.close();
980                            commit(conn);
981                                    
982                    }
983                    catch (Exception e)
984                    {
985                            Log.error("TradeDirect:getHoldings -- error getting user holings", e);
986                            rollBack(conn, e);
987                    }
988                    finally
989                    {
990                            releaseConn(conn);
991                    }
992                    return holdingDataBeans;
993            }
994    
995            /**
996             * @see TradeServices#getHolding(Integer)
997             */
998            public HoldingDataBean getHolding(Integer holdingID) throws Exception {
999                    HoldingDataBean holdingData = null;
1000                    Connection conn=null;
1001                    try
1002                    {
1003                            if (Log.doTrace()) Log.trace("TradeDirect:getHolding - inSession(" + this.inSession + ")", holdingID);
1004                            
1005                            conn = getConn();
1006                            holdingData = getHoldingData(holdingID.intValue());
1007    
1008                            commit(conn);
1009                                    
1010                    }
1011                    catch (Exception e)
1012                    {
1013                            Log.error("TradeDirect:getHolding -- error getting holding " + holdingID + "", e);
1014                            rollBack(conn, e);
1015                    }
1016                    finally
1017                    {
1018                            releaseConn(conn);
1019                    }
1020                    return holdingData;
1021            }       
1022    
1023            /**
1024             * @see TradeServices#getAccountData(String)
1025             */
1026            public AccountDataBean getAccountData(String userID)
1027            throws RemoteException
1028            {
1029            try{
1030                    AccountDataBean accountData = null;
1031                    Connection conn=null;
1032                    try
1033                    {
1034                            if (Log.doTrace()) Log.trace("TradeDirect:getAccountData - inSession(" + this.inSession + ")", userID);
1035                            
1036                            conn = getConn();
1037                            accountData = getAccountData(conn, userID);
1038                            commit(conn);
1039                                    
1040                    }
1041                    catch (Exception e)
1042                    {
1043                            Log.error("TradeDirect:getAccountData -- error getting account data", e);
1044                            rollBack(conn, e);
1045                    }
1046                    finally
1047                    {
1048                            releaseConn(conn);
1049                    }
1050                    return accountData;             
1051            }catch (Exception e){
1052               throw new RemoteException(e.getMessage(),e); 
1053            }
1054            }
1055            private AccountDataBean getAccountData(Connection conn, String userID)
1056            throws Exception
1057            {
1058                    PreparedStatement stmt = getStatement(conn, getAccountForUserSQL);
1059                    stmt.setString(1, userID);
1060                    ResultSet rs = stmt.executeQuery();
1061                    AccountDataBean accountData = getAccountDataFromResultSet(rs);
1062                    stmt.close();
1063                    return accountData;         
1064            }
1065    
1066            private AccountDataBean getAccountDataForUpdate(Connection conn, String userID)
1067            throws Exception
1068            {
1069                    PreparedStatement stmt = getStatement(conn, getAccountForUserForUpdateSQL);
1070                    stmt.setString(1, userID);
1071                    ResultSet rs = stmt.executeQuery();
1072                    AccountDataBean accountData = getAccountDataFromResultSet(rs);
1073                    stmt.close();
1074                    return accountData;         
1075            }
1076            /**
1077             * @see TradeServices#getAccountData(String)
1078             */
1079            public AccountDataBean getAccountData(int accountID)
1080            throws Exception
1081            {
1082                    AccountDataBean accountData = null;
1083                    Connection conn=null;
1084                    try
1085                    {
1086                            if (Log.doTrace()) Log.trace("TradeDirect:getAccountData - inSession(" + this.inSession + ")", new Integer(accountID));
1087                            
1088                            conn = getConn();
1089                            accountData = getAccountData(accountID, conn);
1090                            commit(conn);
1091                                    
1092                    }
1093                    catch (Exception e)
1094                    {
1095                            Log.error("TradeDirect:getAccountData -- error getting account data", e);
1096                            rollBack(conn, e);
1097                    }
1098                    finally
1099                    {
1100                            releaseConn(conn);
1101                    }
1102                    return accountData;             
1103            }
1104            private AccountDataBean getAccountData(int accountID, Connection conn)
1105            throws Exception
1106            {
1107                    PreparedStatement stmt = getStatement(conn, getAccountSQL);
1108                    stmt.setInt(1, accountID);
1109                    ResultSet rs = stmt.executeQuery();
1110                    AccountDataBean accountData = getAccountDataFromResultSet(rs);
1111                    stmt.close();
1112                    return accountData;         
1113            }
1114            private AccountDataBean getAccountDataForUpdate(int accountID, Connection conn)
1115            throws Exception
1116            {
1117                    PreparedStatement stmt = getStatement(conn, getAccountForUpdateSQL);
1118                    stmt.setInt(1, accountID);
1119                    ResultSet rs = stmt.executeQuery();
1120                    AccountDataBean accountData = getAccountDataFromResultSet(rs);
1121                    stmt.close();
1122                    return accountData;         
1123            }       
1124    
1125            private QuoteDataBean getQuoteData(String symbol)
1126            throws Exception
1127            {
1128                    QuoteDataBean quoteData = null;
1129                    Connection conn=null;
1130                    try
1131                    {
1132                            conn = getConn();
1133                            quoteData = getQuoteData(conn, symbol);
1134                            commit(conn);
1135                    }
1136                    catch (Exception e)
1137                    {
1138                            Log.error("TradeDirect:getQuoteData -- error getting data", e);
1139                            rollBack(conn, e);
1140                    }
1141                    finally
1142                    {
1143                            releaseConn(conn);
1144                    }
1145                    return quoteData;               
1146            }
1147            private QuoteDataBean getQuoteData(Connection conn, String symbol)
1148            throws Exception
1149            {
1150                    QuoteDataBean quoteData = null;
1151                    PreparedStatement stmt = getStatement(conn, getQuoteSQL);
1152                    stmt.setString(1, symbol);
1153                    ResultSet rs = stmt.executeQuery();
1154                    if (!rs.next()) 
1155                            Log.error("TradeDirect:getQuoteData -- could not find quote for symbol="+symbol);
1156                    else
1157                            quoteData = getQuoteDataFromResultSet(rs);
1158                    stmt.close();
1159                    return quoteData;         
1160            }
1161            
1162            private HoldingDataBean getHoldingData(int holdingID)
1163            throws Exception
1164            {
1165                    HoldingDataBean holdingData = null;
1166                    Connection conn=null;
1167                    try
1168                    {
1169                            conn = getConn();
1170                            holdingData = getHoldingData(conn, holdingID);
1171                            commit(conn);
1172                    }
1173                    catch (Exception e)
1174                    {
1175                            Log.error("TradeDirect:getHoldingData -- error getting data", e);
1176                            rollBack(conn, e);
1177                    }
1178                    finally
1179                    {
1180                            releaseConn(conn);
1181                    }
1182                    return holdingData;             
1183            }
1184            private HoldingDataBean getHoldingData(Connection conn, int holdingID)
1185            throws Exception
1186            {
1187                    HoldingDataBean holdingData = null;
1188                    PreparedStatement stmt = getStatement(conn, getHoldingSQL);
1189                    stmt.setInt(1, holdingID);
1190                    ResultSet rs = stmt.executeQuery();
1191                    if (!rs.next()) 
1192                            Log.error("TradeDirect:getHoldingData -- no results -- holdingID="+holdingID);
1193                    else
1194                            holdingData = getHoldingDataFromResultSet(rs);
1195    
1196                    stmt.close();
1197                    return holdingData;         
1198            }
1199    
1200            private OrderDataBean getOrderData(int orderID)
1201            throws Exception
1202            {
1203                    OrderDataBean orderData = null;
1204                    Connection conn=null;
1205                    try
1206                    {
1207                            conn = getConn();
1208                            orderData = getOrderData(conn, orderID);
1209                            commit(conn);
1210                    }
1211                    catch (Exception e)
1212                    {
1213                            Log.error("TradeDirect:getOrderData -- error getting data", e);
1214                            rollBack(conn, e);
1215                    }
1216                    finally
1217                    {
1218                            releaseConn(conn);
1219                    }
1220                    return orderData;               
1221            }
1222            private OrderDataBean getOrderData(Connection conn, int orderID)
1223            throws Exception
1224            {
1225                    OrderDataBean orderData = null;
1226                    if (Log.doTrace()) Log.trace("TradeDirect:getOrderData(conn, " + orderID + ")");                
1227                    PreparedStatement stmt = getStatement(conn, getOrderSQL);
1228                    stmt.setInt(1, orderID);
1229                    ResultSet rs = stmt.executeQuery();             
1230                    if (!rs.next())
1231                            Log.error("TradeDirect:getOrderData -- no results for orderID:" + orderID);     
1232                    else
1233                            orderData = getOrderDataFromResultSet(rs);
1234                    stmt.close();
1235                    return orderData;         
1236            }
1237    
1238            
1239            /**
1240             * @see TradeServices#getAccountProfileData(String)
1241             */
1242            public AccountProfileDataBean getAccountProfileData(String userID)
1243            throws Exception
1244            {
1245                    AccountProfileDataBean accountProfileData = null;
1246                    Connection conn=null;
1247            
1248                    try
1249                    {
1250                            if (Log.doTrace()) Log.trace("TradeDirect:getAccountProfileData - inSession(" + this.inSession + ")", userID);
1251                            
1252                            conn = getConn();
1253                            accountProfileData = getAccountProfileData(conn, userID);
1254                            commit(conn);
1255                    }
1256                    catch (Exception e)
1257                    {
1258                            Log.error("TradeDirect:getAccountProfileData -- error getting profile data", e);
1259                            rollBack(conn, e);
1260                    }
1261                    finally
1262                    {
1263                            releaseConn(conn);
1264                    }
1265                    return accountProfileData;              
1266            }
1267            private AccountProfileDataBean getAccountProfileData(Connection conn, String userID)
1268            throws Exception
1269            {
1270                    PreparedStatement stmt = getStatement(conn, getAccountProfileSQL);
1271                    stmt.setString(1, userID);
1272    
1273                    ResultSet rs = stmt.executeQuery();
1274                            
1275                    AccountProfileDataBean accountProfileData = getAccountProfileDataFromResultSet(rs);
1276                    stmt.close();
1277                    return accountProfileData;
1278            }
1279                    
1280    
1281            private AccountProfileDataBean getAccountProfileData(Integer accountID)
1282            throws Exception
1283            {
1284                    AccountProfileDataBean accountProfileData = null;
1285                    Connection conn=null;
1286            
1287                    try
1288                    {
1289                            if (Log.doTrace()) Log.trace("TradeDirect:getAccountProfileData", accountID);
1290                            
1291                            conn = getConn();
1292                            accountProfileData = getAccountProfileData(conn, accountID);
1293                            commit(conn);
1294                    }
1295                    catch (Exception e)
1296                    {
1297                            Log.error("TradeDirect:getAccountProfileData -- error getting profile data", e);
1298                            rollBack(conn, e);
1299                    }
1300                    finally
1301                    {
1302                            releaseConn(conn);
1303                    }
1304                    return accountProfileData;              
1305            }
1306            private AccountProfileDataBean getAccountProfileData(Connection conn, Integer accountID)
1307            throws Exception
1308            {
1309                    PreparedStatement stmt = getStatement(conn, getAccountProfileForAccountSQL);
1310                    stmt.setInt(1, accountID.intValue());
1311    
1312                    ResultSet rs = stmt.executeQuery();
1313                            
1314                    AccountProfileDataBean accountProfileData = getAccountProfileDataFromResultSet(rs);
1315                    stmt.close();
1316                    return accountProfileData;
1317            }
1318            
1319    
1320            /**
1321             * @see TradeServices#updateAccountProfile(AccountProfileDataBean)
1322             */
1323            public AccountProfileDataBean updateAccountProfile(AccountProfileDataBean profileData)
1324            throws Exception {
1325                    AccountProfileDataBean accountProfileData = null;
1326                    Connection conn=null;
1327            
1328                    try
1329                    {
1330                            if (Log.doTrace()) Log.trace("TradeDirect:updateAccountProfileData - inSession(" + this.inSession + ")", profileData.getUserID());
1331                            
1332                            conn = getConn();
1333                            updateAccountProfile(conn, profileData);        
1334    
1335                            accountProfileData = getAccountProfileData(conn, profileData.getUserID());
1336                            commit(conn);
1337                    }
1338                    catch (Exception e)
1339                    {
1340                            Log.error("TradeDirect:getAccountProfileData -- error getting profile data", e);
1341                            rollBack(conn, e);
1342                    }
1343                    finally
1344                    {
1345                            releaseConn(conn);
1346                    }
1347                    return accountProfileData;              
1348            }
1349    
1350            private void creditAccountBalance(Connection conn, AccountDataBean accountData, BigDecimal credit)
1351                    throws Exception
1352            {
1353                    PreparedStatement stmt = getStatement(conn, creditAccountBalanceSQL);
1354    
1355                    stmt.setBigDecimal(1, credit);
1356                    stmt.setInt(2, accountData.getAccountID().intValue());
1357    
1358                    int count = stmt.executeUpdate();
1359                    stmt.close();
1360                    
1361            }
1362    
1363    
1364        // Set Timestamp to zero to denote sell is inflight
1365        // UPDATE  -- could add a "status" attribute to holding
1366            private void updateHoldingStatus(Connection conn, Integer holdingID, String symbol)
1367                    throws Exception
1368            {
1369                    Timestamp ts = new Timestamp(0);
1370                    PreparedStatement stmt = getStatement(conn, "update holdingejb set purchasedate= ? where holdingid = ?");
1371    
1372                    stmt.setTimestamp(1, ts);
1373                    stmt.setInt(2, holdingID.intValue());
1374                    int count = stmt.executeUpdate();
1375                    stmt.close();   
1376            }
1377    
1378            private void updateOrderStatus(Connection conn, Integer orderID, String status)
1379                    throws Exception
1380            {
1381                    PreparedStatement stmt = getStatement(conn, updateOrderStatusSQL);
1382    
1383                    stmt.setString(1, status);
1384                    stmt.setTimestamp(2, new Timestamp(System.currentTimeMillis()));
1385                    stmt.setInt(3, orderID.intValue());
1386                    int count = stmt.executeUpdate();
1387                    stmt.close();   
1388            }
1389            
1390            private void updateOrderHolding(Connection conn, int orderID, int holdingID)
1391                    throws Exception
1392            {
1393                    PreparedStatement stmt = getStatement(conn, updateOrderHoldingSQL);
1394    
1395                    stmt.setInt(1, holdingID);
1396                    stmt.setInt(2, orderID);
1397                    int count = stmt.executeUpdate();
1398                    stmt.close();   
1399            }
1400            
1401            private void updateAccountProfile(Connection conn, AccountProfileDataBean profileData)
1402                    throws Exception        
1403            {
1404                    PreparedStatement stmt = getStatement(conn, updateAccountProfileSQL);
1405    
1406                    stmt.setString(1, profileData.getPassword());
1407                    stmt.setString(2, profileData.getFullName());
1408                    stmt.setString(3, profileData.getAddress());
1409                    stmt.setString(4, profileData.getEmail());
1410                    stmt.setString(5, profileData.getCreditCard());
1411                    stmt.setString(6, profileData.getUserID());                                                            
1412    
1413                    int count = stmt.executeUpdate();
1414                    stmt.close();
1415            }
1416            
1417            private void updateQuoteVolume(Connection conn, QuoteDataBean quoteData, double quantity)
1418                    throws Exception        
1419            {
1420                    PreparedStatement stmt = getStatement(conn, updateQuoteVolumeSQL);
1421    
1422                    stmt.setDouble(1, quantity);
1423                    stmt.setString(2, quoteData.getSymbol());
1424    
1425                    int count = stmt.executeUpdate();
1426                    stmt.close();   
1427            }
1428    
1429            public QuoteDataBean updateQuotePriceVolume(String symbol, BigDecimal changeFactor, double sharesTraded) throws Exception {
1430                    return updateQuotePriceVolumeInt(symbol, changeFactor, sharesTraded, publishQuotePriceChange);
1431            }
1432    
1433            /**
1434             * Update a quote's price and volume
1435             * @param symbol The PK of the quote
1436             * @param changeFactor the percent to change the old price by (between 50% and 150%)
1437             * @param sharedTraded the ammount to add to the current volume
1438             * @param publishQuotePriceChange used by the PingJDBCWrite Primitive to ensure no JMS is used, should
1439             *   be true for all normal calls to this API
1440             */
1441            public QuoteDataBean updateQuotePriceVolumeInt(String symbol, BigDecimal changeFactor, double sharesTraded, boolean publishQuotePriceChange)
1442                    throws Exception        
1443            {
1444                    
1445                    if ( TradeConfig.getUpdateQuotePrices() == false ) 
1446                            return new QuoteDataBean();     
1447                    
1448                    QuoteDataBean quoteData = null;
1449                    Connection conn=null;
1450                    UserTransaction txn = null;
1451                    try
1452                    {
1453                            if (Log.doTrace()) Log.trace("TradeDirect:updateQuotePriceVolume - inSession(" + this.inSession + ")", symbol, changeFactor, new Double(sharesTraded));         
1454    
1455                            conn = getConn();
1456    
1457                            quoteData = getQuoteForUpdate(conn, symbol);
1458                            BigDecimal oldPrice = quoteData.getPrice();
1459                            double newVolume = quoteData.getVolume() + sharesTraded;
1460    
1461                            if (oldPrice.equals(TradeConfig.PENNY_STOCK_PRICE)) {
1462                                    changeFactor = TradeConfig.PENNY_STOCK_RECOVERY_MIRACLE_MULTIPLIER;
1463                            }
1464    
1465                            BigDecimal newPrice = changeFactor.multiply(oldPrice).setScale(2, BigDecimal.ROUND_HALF_UP);
1466    
1467                            updateQuotePriceVolume(conn, quoteData.getSymbol(), newPrice, newVolume);                               
1468                            quoteData = getQuote(conn, symbol);
1469    
1470                            commit(conn);           
1471    
1472                            if (publishQuotePriceChange) {
1473                                    publishQuotePriceChange(quoteData, oldPrice, changeFactor, sharesTraded);                       
1474                            }
1475                            
1476                    }
1477                    catch (Exception e)
1478                    {
1479                            Log.error("TradeDirect:updateQuotePriceVolume -- error updating quote price/volume for symbol:" + symbol);
1480                            rollBack(conn, e);
1481                            throw e;
1482                    }
1483                    finally
1484                    {
1485                            releaseConn(conn);
1486                    }
1487                    return quoteData;               
1488            }
1489    
1490            private void updateQuotePriceVolume(Connection conn, String symbol, BigDecimal newPrice, double newVolume)
1491                    throws Exception        
1492            {               
1493    
1494                    PreparedStatement stmt = getStatement(conn, updateQuotePriceVolumeSQL);
1495    
1496                    stmt.setBigDecimal(1, newPrice);
1497                    stmt.setBigDecimal(2, newPrice);                
1498                    stmt.setDouble(3, newVolume);                           
1499                    stmt.setString(4, symbol);
1500    
1501                    int count = stmt.executeUpdate();
1502                    stmt.close();   
1503            }
1504            private void publishQuotePriceChange(QuoteDataBean quoteData, BigDecimal oldPrice, BigDecimal changeFactor, double sharesTraded)
1505            throws Exception
1506            {
1507                    if (Log.doTrace())
1508                            Log.trace("TradeDirect:publishQuotePrice PUBLISHING to MDB quoteData = " + quoteData);          
1509    
1510                    javax.jms.Connection conn = null;       
1511                    Session sess = null;
1512                    
1513                    try
1514                    {
1515                            conn = tConnFactory.createConnection();                                                         
1516                            sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
1517                            MessageProducer producer = sess.createProducer(streamerTopic);
1518                            TextMessage message = sess.createTextMessage();
1519            
1520                            String command = "updateQuote";
1521                            message.setStringProperty("command", command);
1522                            message.setStringProperty("symbol",  quoteData.getSymbol() );
1523                            message.setStringProperty("company", quoteData.getCompanyName() );              
1524                            message.setStringProperty("price",   quoteData.getPrice().toString());
1525                            message.setStringProperty("oldPrice",oldPrice.toString());                              
1526                            message.setStringProperty("open",    quoteData.getOpen().toString());
1527                            message.setStringProperty("low",     quoteData.getLow().toString());
1528                            message.setStringProperty("high",    quoteData.getHigh().toString());
1529                            message.setDoubleProperty("volume",  quoteData.getVolume());            
1530                                            
1531                            message.setStringProperty("changeFactor", changeFactor.toString());             
1532                            message.setDoubleProperty("sharesTraded", sharesTraded);                                
1533                            message.setLongProperty("publishTime", System.currentTimeMillis());                                     
1534                            message.setText("Update Stock price for " + quoteData.getSymbol() + " old price = " + oldPrice + " new price = " + quoteData.getPrice());
1535    
1536                            producer.send(message);
1537                    }
1538                    catch (Exception e)
1539                    {
1540                            throw e; //pass exception back
1541                            
1542                    }
1543                    
1544                    finally
1545                    {
1546                            if (conn != null)
1547                                    conn.close();
1548                            if (sess != null)       
1549                                    sess.close();                                   
1550                    }       
1551            }               
1552    
1553    
1554            /**
1555             * @see TradeServices#login(String, String)
1556             */
1557            
1558            public AccountDataBean login(String userID, String password)
1559            throws Exception {
1560    
1561                    AccountDataBean accountData = null;
1562                    Connection conn=null;
1563                    try
1564                    {
1565                            if (Log.doTrace()) Log.trace("TradeDirect:login - inSession(" + this.inSession + ")", userID, password);
1566                            
1567                            conn = getConn();
1568                PreparedStatement stmt = getStatement(conn, getAccountProfileSQL);
1569                stmt.setString(1, userID);
1570    
1571                            ResultSet rs = stmt.executeQuery();
1572                            if ( !rs.next() )
1573                            {
1574                                    Log.error("TradeDirect:login -- failure to find account for" + userID);
1575                                    throw new javax.ejb.FinderException("Cannot find account for" + userID);
1576                            }
1577                                    
1578                            String pw = rs.getString("passwd");
1579                            stmt.close();
1580                    if ( (pw==null) || (pw.equals(password) == false) )
1581                    {
1582                                    String error = "TradeDirect:Login failure for user: " + userID + 
1583                                                    "\n\tIncorrect password-->" + userID + ":" + password;
1584                            Log.error(error);
1585                                    throw new Exception(error);
1586                    }
1587                    
1588                            stmt = getStatement(conn, loginSQL);
1589                            stmt.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
1590                            stmt.setString(2, userID);
1591    
1592                            int rows = stmt.executeUpdate();
1593                            //?assert rows==1?
1594                            stmt.close();
1595            
1596                            stmt = getStatement(conn, getAccountForUserSQL);
1597                            stmt.setString(1, userID);
1598                            rs = stmt.executeQuery();
1599    
1600                            accountData = getAccountDataFromResultSet(rs);
1601                            
1602                            stmt.close();
1603                    
1604                            commit(conn);
1605                    }
1606                    catch (Exception e)
1607                    {
1608                            Log.error("TradeDirect:login -- error logging in user", e);
1609                            rollBack(conn, e);
1610                    }
1611                    finally
1612                    {
1613                            releaseConn(conn);
1614                    }
1615                    return accountData;             
1616    
1617                    /*
1618            setLastLogin( new Timestamp(System.currentTimeMillis()) );
1619            setLoginCount( getLoginCount() + 1 );
1620            */
1621            }
1622            
1623            /**
1624             * @see TradeServices#logout(String)
1625             */
1626            public void logout(String userID) throws Exception {
1627                    if (Log.doTrace()) Log.trace("TradeDirect:logout - inSession(" + this.inSession + ")", userID);
1628                    Connection conn=null;
1629                    try
1630                    {               
1631                            conn = getConn();
1632                PreparedStatement stmt = getStatement(conn, logoutSQL);
1633                stmt.setString(1, userID);        
1634                            stmt.executeUpdate();
1635                            stmt.close();
1636    
1637                            commit(conn);
1638                    }
1639                    catch (Exception e)
1640                    {
1641                            Log.error("TradeDirect:logout -- error logging out user", e);
1642                            rollBack(conn, e);
1643                    }
1644                    finally
1645                    {
1646                            releaseConn(conn);
1647                    }
1648            }
1649    
1650            /**
1651             * @see TradeServices#register(String, String, String, String, String, String, BigDecimal, boolean)
1652             */
1653    
1654            public AccountDataBean register(
1655                    String userID,
1656                    String password,
1657                    String fullname,
1658                    String address,
1659                    String email,
1660                    String creditcard,
1661                    BigDecimal openBalance)
1662                    throws Exception {
1663                            
1664                    AccountDataBean accountData = null;
1665                    Connection conn=null;
1666                    try
1667                    {
1668                            if (Log.doTrace()) Log.traceEnter("TradeDirect:register - inSession(" + this.inSession + ")");
1669                            
1670                            conn = getConn();
1671                PreparedStatement stmt = getStatement(conn, createAccountSQL);
1672    
1673                            Integer accountID = KeySequenceDirect.getNextID(conn, "account", inSession, getInGlobalTxn());
1674                            BigDecimal balance = openBalance;
1675                            Timestamp creationDate = new Timestamp(System.currentTimeMillis());
1676                            Timestamp lastLogin  = creationDate;
1677                            int  loginCount = 0;
1678                            int  logoutCount = 0;
1679                            
1680                stmt.setInt(1, accountID.intValue());                       
1681                stmt.setTimestamp(2, creationDate);
1682                stmt.setBigDecimal(3, openBalance);
1683                stmt.setBigDecimal(4, balance);  
1684                stmt.setTimestamp(5, lastLogin);
1685                stmt.setInt(6, loginCount);
1686                stmt.setInt(7, logoutCount);
1687                stmt.setString(8, userID);        
1688                            stmt.executeUpdate();
1689                            stmt.close();
1690                            
1691                stmt = getStatement(conn, createAccountProfileSQL);
1692                            stmt.setString(1, userID);        
1693                            stmt.setString(2, password);        
1694                            stmt.setString(3, fullname);
1695                            stmt.setString(4, address);
1696                            stmt.setString(5, email);                       
1697                            stmt.setString(6, creditcard);
1698                            stmt.executeUpdate();
1699                            stmt.close();
1700                                                                            
1701                            commit(conn);
1702                                    
1703                            accountData = new AccountDataBean(accountID, loginCount, logoutCount, lastLogin, creationDate, balance, openBalance, userID);
1704                            if (Log.doTrace()) Log.traceExit("TradeDirect:register");
1705                    }
1706                    catch (Exception e)
1707                    {
1708                            Log.error("TradeDirect:register -- error registering new user", e);
1709                    }
1710                    finally
1711                    {
1712                            releaseConn(conn);
1713                    }
1714                    return accountData;
1715            }
1716    
1717            private AccountDataBean getAccountDataFromResultSet(ResultSet rs)
1718            throws Exception
1719            {
1720                    AccountDataBean accountData = null;
1721    
1722    
1723                    if (!rs.next() )
1724                            Log.error("TradeDirect:getAccountDataFromResultSet -- cannot find account data");
1725                                    
1726                    else
1727                            accountData = new AccountDataBean(
1728                                    new Integer(rs.getInt("accountID")),
1729                                    rs.getInt("loginCount"),
1730                                    rs.getInt("logoutCount"),
1731                                    rs.getTimestamp("lastLogin"),
1732                                    rs.getTimestamp("creationDate"),
1733                                    rs.getBigDecimal("balance"),
1734                                    rs.getBigDecimal("openBalance"),
1735                                    rs.getString("profile_userID")                  
1736                            );
1737                    return accountData;
1738            }
1739    
1740            private AccountProfileDataBean getAccountProfileDataFromResultSet(ResultSet rs)
1741            throws Exception
1742            {
1743                    AccountProfileDataBean accountProfileData = null;
1744    
1745                    if (!rs.next() )
1746                            Log.error("TradeDirect:getAccountProfileDataFromResultSet -- cannot find accountprofile data");
1747                    else                    
1748                            accountProfileData = new AccountProfileDataBean(
1749                                    rs.getString("userID"),
1750                                    rs.getString("passwd"),
1751                                    rs.getString("fullName"),
1752                                    rs.getString("address"),
1753                                    rs.getString("email"),
1754                                    rs.getString("creditCard")
1755                            );
1756                            
1757                    return accountProfileData;
1758            }
1759    
1760            private HoldingDataBean getHoldingDataFromResultSet(ResultSet rs)
1761            throws Exception
1762            {
1763                    HoldingDataBean holdingData = null;
1764    
1765                    holdingData = new HoldingDataBean(
1766                            new Integer(rs.getInt("holdingID")),
1767                            rs.getDouble("quantity"),
1768                            rs.getBigDecimal("purchasePrice"),
1769                            rs.getTimestamp("purchaseDate"),
1770                            rs.getString("quote_symbol")
1771                    );
1772                    return holdingData;
1773            }
1774            
1775            private QuoteDataBean getQuoteDataFromResultSet(ResultSet rs)
1776            throws Exception
1777            {
1778                    QuoteDataBean quoteData = null;
1779    
1780                    quoteData = new QuoteDataBean(
1781                            rs.getString("symbol"),
1782                            rs.getString("companyName"),
1783                            rs.getDouble("volume"),
1784                            rs.getBigDecimal("price"),
1785                            rs.getBigDecimal("open1"),
1786                            rs.getBigDecimal("low"),
1787                            rs.getBigDecimal("high"),
1788                            rs.getDouble("change1")
1789                    );
1790                    return quoteData;
1791            }
1792    
1793            private OrderDataBean getOrderDataFromResultSet(ResultSet rs)
1794            throws Exception
1795            {
1796                    OrderDataBean orderData = null;
1797    
1798                    orderData = new OrderDataBean(
1799                            new Integer(rs.getInt("orderID")),
1800                            rs.getString("orderType"),
1801                            rs.getString("orderStatus"),
1802                            rs.getTimestamp("openDate"),
1803                            rs.getTimestamp("completionDate"),
1804                            rs.getDouble("quantity"),
1805                            rs.getBigDecimal("price"),
1806                            rs.getBigDecimal("orderFee"),
1807                            rs.getString("quote_symbol")
1808                    );
1809                    return orderData;
1810            }
1811            
1812            public String checkDBProductName() throws Exception
1813            {
1814                    Connection conn = null;
1815                    String dbProductName = null;
1816                    
1817                    try
1818                    {
1819                            if (Log.doTrace()) Log.traceEnter("TradeDirect:checkDBProductName");
1820                            
1821                            conn = getConn();
1822                            DatabaseMetaData dbmd = conn.getMetaData();
1823                            dbProductName = dbmd.getDatabaseProductName();
1824                    }
1825                    catch (SQLException e)
1826                    {
1827                            Log.error(e,"TradeDirect:checkDBProductName() -- Error checking the Daytrader Database Product Name");
1828                    }
1829                    finally
1830                    {
1831                            releaseConn(conn);
1832                    }
1833                    return dbProductName;
1834            }
1835            
1836            public boolean recreateDBTables(Object[] sqlBuffer, java.io.PrintWriter out) throws Exception
1837            {
1838                    //Clear MDB Statistics          
1839                    MDBStats.getInstance().reset();
1840                    
1841                    Connection conn = null;
1842                    boolean success = false;
1843                    try
1844                    {
1845                            if (Log.doTrace()) Log.traceEnter("TradeDirect:recreateDBTables");
1846                            
1847                            conn = getConn();
1848                            Statement stmt = conn.createStatement();
1849                            int bufferLength = sqlBuffer.length;
1850                            for (int i = 0; i< bufferLength; i++)
1851                            {
1852                                    try
1853                                    {
1854                                            stmt.executeUpdate((String)sqlBuffer[i]);
1855                                            //commit(conn);
1856                                    }
1857                                    catch(SQLException ex) 
1858                                    {
1859                            Log.error("TradeDirect:recreateDBTables SQL Exception thrown on executing the foll sql command: " + sqlBuffer[i], ex);
1860                            out.println("<BR>SQL Exception thrown on executing the foll sql command: <I>" + sqlBuffer[i] + "</I> . Check log for details.</BR>");
1861                    }
1862                            }
1863                            stmt.close();
1864                commit(conn);
1865                success = true;
1866                    }
1867                    catch (Exception e)
1868                    {
1869                            Log.error(e,"TradeDirect:recreateDBTables() -- Error dropping and recreating the database tables");
1870                    }
1871                    finally
1872                    {
1873                            releaseConn(conn);
1874                    }
1875                    return success;
1876            }
1877            
1878            public RunStatsDataBean resetTrade(boolean deleteAll)
1879            throws Exception
1880            {
1881                    //Clear MDB Statistics          
1882                    MDBStats.getInstance().reset();
1883                    // Reset Trade          
1884    
1885                    RunStatsDataBean runStatsData = new RunStatsDataBean();
1886                    Connection conn=null;
1887                    try
1888                    {
1889                            if (Log.doTrace()) Log.traceEnter("TradeDirect:resetTrade deleteAll rows=" + deleteAll);
1890            
1891                            conn = getConn();
1892                            PreparedStatement stmt=null;
1893                            ResultSet rs = null;
1894                            
1895                            if (deleteAll)
1896                            {
1897                                    try
1898                                    {
1899                                            stmt = getStatement(conn, "delete from quoteejb");
1900                                            stmt.executeUpdate();
1901                                            stmt.close();                           
1902                                            stmt = getStatement(conn, "delete from accountejb");
1903                                            stmt.executeUpdate();
1904                                            stmt.close();
1905                                            stmt = getStatement(conn, "delete from accountprofileejb");
1906                                            stmt.executeUpdate();
1907                                            stmt.close();
1908                                            stmt = getStatement(conn, "delete from holdingejb");
1909                                            stmt.executeUpdate();
1910                                            stmt.close();
1911                                            stmt = getStatement(conn, "delete from orderejb");
1912                                            stmt.executeUpdate();
1913                                            stmt.close();
1914                                            // FUTURE: - DuplicateKeyException - For now, don't start at
1915                                            // zero as KeySequenceDirect and KeySequenceBean will still give out
1916                                            // the cached Block and then notice this change.  Better solution is
1917                                            // to signal both classes to drop their cached blocks
1918                                            //stmt = getStatement(conn, "delete from keygenejb");
1919                                            //stmt.executeUpdate();
1920                                            //stmt.close();
1921                                            commit(conn);
1922                                    }
1923                                    catch (Exception e)
1924                                    {
1925                                            Log.error(e,"TradeDirect:resetTrade(deleteAll) -- Error deleting Trade users and stock from the Trade database");
1926                                    }
1927                                    return runStatsData;
1928                            }
1929    
1930                stmt = getStatement(conn, "delete from holdingejb where holdingejb.account_accountid is null");
1931                int x = stmt.executeUpdate();
1932                stmt.close();                       
1933                            
1934                            //Count and Delete newly registered users (users w/ id that start "ru:%":
1935                stmt = getStatement(conn, "delete from accountprofileejb where userid like 'ru:%'");
1936                int rowCount = stmt.executeUpdate();
1937                stmt.close();
1938                            
1939                stmt = getStatement(conn, "delete from orderejb where account_accountid in (select accountid from accountejb a where a.profile_userid like 'ru:%')");
1940                rowCount = stmt.executeUpdate();
1941                stmt.close();
1942    
1943                stmt = getStatement(conn, "delete from holdingejb where account_accountid in (select accountid from accountejb a where a.profile_userid like 'ru:%')");
1944                rowCount = stmt.executeUpdate();
1945                stmt.close();
1946                
1947                stmt = getStatement(conn, "delete from accountejb where profile_userid like 'ru:%'");
1948                int newUserCount = stmt.executeUpdate();
1949                runStatsData.setNewUserCount(newUserCount);
1950                stmt.close();           
1951    
1952                            //Count of trade users                  
1953                stmt = getStatement(conn, "select count(accountid) as \"tradeUserCount\" from accountejb a where a.profile_userid like 'uid:%'");
1954                rs = stmt.executeQuery();
1955                rs.next();
1956                int tradeUserCount = rs.getInt("tradeUserCount");
1957                runStatsData.setTradeUserCount(tradeUserCount);
1958                stmt.close();
1959                
1960                rs.close();
1961                            //Count of trade stocks                 
1962                stmt = getStatement(conn, "select count(symbol) as \"tradeStockCount\" from quoteejb a where a.symbol like 's:%'");
1963                rs = stmt.executeQuery();
1964                rs.next();
1965                int tradeStockCount = rs.getInt("tradeStockCount");
1966                runStatsData.setTradeStockCount(tradeStockCount);
1967                stmt.close();
1968               
1969    
1970                            //Count of trade users login, logout
1971                stmt = getStatement(conn, "select sum(loginCount) as \"sumLoginCount\", sum(logoutCount) as \"sumLogoutCount\" from accountejb a where  a.profile_userID like 'uid:%'");
1972                rs = stmt.executeQuery();
1973                rs.next();
1974                int sumLoginCount  = rs.getInt("sumLoginCount");
1975                int sumLogoutCount = rs.getInt("sumLogoutCount");
1976                runStatsData.setSumLoginCount(sumLoginCount);
1977                runStatsData.setSumLogoutCount(sumLogoutCount);            
1978                stmt.close();
1979                
1980                rs.close();
1981                            //Update logoutcount and loginCount back to zero
1982                
1983                stmt = getStatement(conn, "update accountejb set logoutCount=0,loginCount=0 where profile_userID like 'uid:%'");
1984                rowCount = stmt.executeUpdate();
1985                stmt.close();
1986    
1987                            //count holdings for trade users
1988                stmt = getStatement(conn, "select count(holdingid) as \"holdingCount\" from holdingejb h where h.account_accountid in "
1989                                                                    + "(select accountid from accountejb a where a.profile_userid like 'uid:%')");
1990                
1991                rs = stmt.executeQuery();
1992                rs.next();
1993                            int holdingCount = rs.getInt("holdingCount");
1994                runStatsData.setHoldingCount(holdingCount);
1995                stmt.close();
1996                rs.close();
1997    
1998    
1999                            //count orders for trade users
2000                stmt = getStatement(conn, "select count(orderid) as \"orderCount\" from orderejb o where o.account_accountid in "
2001                                                                    + "(select accountid from accountejb a where a.profile_userid like 'uid:%')");
2002                
2003                rs = stmt.executeQuery();
2004                rs.next();
2005                            int orderCount = rs.getInt("orderCount");
2006                runStatsData.setOrderCount(orderCount);
2007                stmt.close();
2008                rs.close();
2009    
2010                            //count orders by type for trade users
2011                stmt = getStatement(conn, "select count(orderid) \"buyOrderCount\"from orderejb o where (o.account_accountid in "
2012                                                                                    + "(select accountid from accountejb a where a.profile_userid like 'uid:%')) AND "
2013                                                                                    + " (o.orderType='buy')");
2014                
2015                rs = stmt.executeQuery();
2016                rs.next();
2017                            int buyOrderCount = rs.getInt("buyOrderCount");
2018                runStatsData.setBuyOrderCount(buyOrderCount);                       
2019                stmt.close();
2020                rs.close();
2021    
2022    
2023                            //count orders by type for trade users
2024                stmt = getStatement(conn, "select count(orderid) \"sellOrderCount\"from orderejb o where (o.account_accountid in "
2025                                                                                    + "(select accountid from accountejb a where a.profile_userid like 'uid:%')) AND "
2026                                                                                    + " (o.orderType='sell')");
2027                
2028                rs = stmt.executeQuery();
2029                rs.next();
2030                            int sellOrderCount = rs.getInt("sellOrderCount");
2031                runStatsData.setSellOrderCount(sellOrderCount);                                             
2032                stmt.close();
2033                rs.close();
2034    
2035    
2036                            //Delete cancelled orders 
2037                stmt = getStatement(conn, "delete from orderejb where orderStatus='cancelled'");
2038                int cancelledOrderCount = stmt.executeUpdate();
2039                runStatsData.setCancelledOrderCount(cancelledOrderCount);
2040                stmt.close();
2041                rs.close();
2042    
2043                            //count open orders by type for trade users
2044                stmt = getStatement(conn, "select count(orderid) \"openOrderCount\"from orderejb o where (o.account_accountid in "
2045                                                                                    + "(select accountid from accountejb a where a.profile_userid like 'uid:%')) AND "
2046                                                                                    + " (o.orderStatus='open')");
2047                
2048                rs = stmt.executeQuery();
2049                rs.next();
2050                            int openOrderCount = rs.getInt("openOrderCount");
2051                runStatsData.setOpenOrderCount(openOrderCount);                     
2052    
2053    
2054                stmt.close();
2055                rs.close();
2056                            //Delete orders for holding which have been purchased and sold 
2057                stmt = getStatement(conn, "delete from orderejb where holding_holdingid is null");
2058                int deletedOrderCount = stmt.executeUpdate();
2059                runStatsData.setDeletedOrderCount(deletedOrderCount);
2060                stmt.close();
2061                rs.close();
2062            
2063                            commit(conn); 
2064                            
2065                            System.out.println("TradeDirect:reset Run stats data\n\n" + runStatsData);        
2066                    }
2067                    catch (Exception e)
2068                    {
2069                            Log.error(e, "Failed to reset Trade");
2070                            rollBack(conn, e);
2071                            throw e;
2072                    }
2073                    finally
2074                    {
2075                            releaseConn(conn);
2076                    }
2077                    return runStatsData;            
2078                    
2079            }
2080    
2081            private void releaseConn(Connection conn)
2082                    throws Exception
2083            {
2084                    try 
2085                    {
2086                            if ( conn!= null )
2087                            {
2088                                    conn.close();
2089                                    if (Log.doTrace())
2090                                    {
2091                                            synchronized(lock)
2092                                            {
2093                                                    connCount--;
2094                                            }
2095                                            Log.trace("TradeDirect:releaseConn -- connection closed, connCount="+connCount);                                
2096                                    }
2097                            }
2098                    }
2099                    catch (Exception e)
2100                    {
2101                            Log.error("TradeDirect:releaseConnection -- failed to close connection", e);
2102                    }
2103            }
2104    
2105       /*
2106        * Lookup the TradeData datasource
2107        *
2108        */
2109            private void getDataSource() throws Exception 
2110            {
2111                    datasource = (DataSource) context.lookup(dsName);
2112            }
2113            
2114    
2115       /*
2116        * Allocate a new connection to the datasource
2117        *
2118        */
2119        private static int connCount=0;
2120        private static Integer lock = new Integer(0);
2121            private Connection getConn() throws Exception 
2122            {
2123            
2124                    Connection conn = null;
2125                    if ( datasource == null )
2126                            getDataSource();
2127                    conn = datasource.getConnection();
2128                    conn.setAutoCommit(false);
2129                    if (Log.doTrace())
2130                    {
2131                            synchronized(lock)
2132                            {
2133                                    connCount++;
2134                            }
2135                            Log.trace("TradeDirect:getConn -- new connection allocated, IsolationLevel=" + conn.getTransactionIsolation() + " connectionCount = " + connCount);
2136                    }
2137    
2138                    return conn;
2139            }
2140    
2141       /*
2142        * Commit the provided connection if not under Global Transaction scope
2143        * - conn.commit() is not allowed in a global transaction. the txn manager will
2144        *   perform the commit
2145        */  
2146            private void commit(Connection conn)
2147            throws Exception
2148            {
2149                    if (!inSession) {
2150                            if ( (getInGlobalTxn()==false) && (conn != null) )
2151                                    conn.commit();
2152                    }
2153            }
2154            
2155    
2156       /*
2157        * Rollback the statement for the given connection
2158        *
2159        */
2160       private void rollBack(Connection conn, Exception e) 
2161       throws Exception 
2162       {
2163                    if (!inSession) {
2164                            Log.log("TradeDirect:rollBack -- rolling back conn due to previously caught exception -- inGlobalTxn=" + getInGlobalTxn());
2165                            if ( (getInGlobalTxn()==false) && (conn != null) )
2166                            conn.rollback();
2167                    else
2168                            throw e;  // Throw the exception 
2169                                              // so the Global txn manager will rollBack
2170                    }       
2171       }    
2172            
2173       /*
2174        * Allocate a new prepared statment for this connection
2175        *
2176        */
2177            private PreparedStatement getStatement(Connection conn, String sql) throws Exception {
2178          return conn.prepareStatement(sql);
2179            }
2180            private PreparedStatement getStatement(Connection conn, String sql, int type, int concurrency) throws Exception {   
2181          return conn.prepareStatement(sql, type, concurrency );
2182            }
2183            
2184            
2185            private static final String createQuoteSQL =
2186                    "insert into quoteejb " +
2187                    "( symbol, companyName, volume, price, open1, low, high, change1 ) " +
2188                    "VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  )";
2189    
2190            private static final String createAccountSQL =
2191                    "insert into accountejb " +
2192                    "( accountid, creationDate, openBalance, balance, lastLogin, loginCount, logoutCount, profile_userid) " +
2193                    "VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  )";
2194    
2195            private static final String createAccountProfileSQL =
2196                    "insert into accountprofileejb " +
2197                    "( userid, passwd, fullname, address, email, creditcard ) " +
2198                    "VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  )";
2199    
2200            private static final String createHoldingSQL  = 
2201                    "insert into holdingejb " +
2202                    "( holdingid, purchaseDate, purchasePrice, quantity, quote_symbol, account_accountid ) " +
2203                    "VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ? )";
2204    
2205            private static final String createOrderSQL = 
2206                    "insert into orderejb " +
2207                    "( orderid, ordertype, orderstatus, opendate, quantity, price, orderfee, account_accountid,  holding_holdingid, quote_symbol) " +
2208                    "VALUES (  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  ,  ?  , ? , ? , ?)";
2209    
2210            private static final String removeHoldingSQL  = 
2211                    "delete from holdingejb where holdingid = ?";
2212    
2213            private static final String removeHoldingFromOrderSQL  =                
2214                    "update orderejb set holding_holdingid=null where holding_holdingid = ?";
2215            
2216            private final static String updateAccountProfileSQL = 
2217                    "update accountprofileejb set " +
2218                    "passwd = ?, fullname = ?, address = ?, email = ?, creditcard = ? " +
2219                    "where userid = (select profile_userid from accountejb a " +
2220                    "where a.profile_userid=?)";
2221    
2222            private final static String loginSQL=
2223                    "update accountejb set lastLogin=?, logincount=logincount+1 " +
2224                    "where profile_userid=?";
2225    
2226            private static final String logoutSQL = 
2227                    "update accountejb set logoutcount=logoutcount+1 " +
2228                    "where profile_userid=?";
2229            
2230            private static final String getAccountSQL  = 
2231                    "select * from accountejb a where a.accountid = ?";
2232    
2233            private static final String getAccountForUpdateSQL  = 
2234                    "select * from accountejb a where a.accountid = ? for update";
2235    
2236            private final static String getAccountProfileSQL = 
2237                    "select * from accountprofileejb ap where ap.userid = " + 
2238                    "(select profile_userid from accountejb a where a.profile_userid=?)";
2239    
2240            private final static String getAccountProfileForAccountSQL = 
2241                    "select * from accountprofileejb ap where ap.userid = " + 
2242                    "(select profile_userid from accountejb a where a.accountid=?)";
2243    
2244            private static final String getAccountForUserSQL  = 
2245                    "select * from accountejb a where a.profile_userid = " +
2246                    "( select userid from accountprofileejb ap where ap.userid = ?)";
2247    
2248            private static final String getAccountForUserForUpdateSQL  = 
2249                    "select * from accountejb a where a.profile_userid = " +
2250                    "( select userid from accountprofileejb ap where ap.userid = ?) for update";
2251    
2252            private static final String getHoldingSQL  = 
2253                    "select * from holdingejb h where h.holdingid = ?";
2254    
2255            private static final String getHoldingsForUserSQL  = 
2256                    "select * from holdingejb h where h.account_accountid = " +
2257                    "(select a.accountid from accountejb a where a.profile_userid = ?)";
2258                    
2259            private static final String getOrderSQL  = 
2260                    "select * from orderejb o where o.orderid = ?";
2261    
2262            private static final String getOrdersByUserSQL  = 
2263                    "select * from orderejb o where o.account_accountid = " +
2264                    "(select a.accountid from accountejb a where a.profile_userid = ?)";
2265    
2266            private static final String getClosedOrdersSQL  = 
2267                    "select * from orderejb o " +
2268                    "where o.orderstatus = 'closed' AND o.account_accountid = " +
2269                    "(select a.accountid from accountejb a where a.profile_userid = ?)";
2270    
2271            private static final String getQuoteSQL  = 
2272                    "select * from quoteejb q where q.symbol=?";
2273    
2274            private static final String getAllQuotesSQL = 
2275                    "select * from quoteejb q";
2276    
2277            private static final String getQuoteForUpdateSQL  = 
2278                    "select * from quoteejb q where q.symbol=? For Update";
2279            
2280            private static final String getTSIAQuotesOrderByChangeSQL  = 
2281                    "select * from quoteejb q " +
2282                    "where q.symbol like 's:1__' order by q.change1";
2283    
2284            private static final String getTSIASQL  = 
2285                    "select SUM(price)/count(*) as TSIA from quoteejb q " +
2286                    "where q.symbol like 's:1__'";
2287    
2288            private static final String getOpenTSIASQL  = 
2289                    "select SUM(open1)/count(*) as openTSIA from quoteejb q " +
2290                    "where q.symbol like 's:1__'";
2291    
2292            private static final String getTSIATotalVolumeSQL =
2293                    "select SUM(volume) as totalVolume from quoteejb q " +
2294                    "where q.symbol like 's:1__'";          
2295                    
2296            private static final String creditAccountBalanceSQL =
2297                    "update accountejb set " +
2298                    "balance = balance + ? " +
2299                    "where accountid = ?";
2300    
2301            private static final String updateOrderStatusSQL =
2302                    "update orderejb set " +
2303                    "orderstatus = ?, completiondate = ? " +
2304                    "where orderid = ?";
2305            
2306            private static final String updateOrderHoldingSQL =
2307                    "update orderejb set " +
2308                    "holding_holdingID = ? " +
2309                    "where orderid = ?";    
2310                    
2311            private static final String updateQuoteVolumeSQL =
2312                    "update quoteejb set " +
2313                    "volume = volume + ? " +
2314                    "where symbol = ?";
2315    
2316            private static final String updateQuotePriceVolumeSQL =
2317                    "update quoteejb set " +
2318                    "price = ?, change1 = ? - open1, volume = ? " +
2319                    "where symbol = ?";
2320                    
2321            
2322    
2323    
2324            private static boolean initialized = false;
2325            public static synchronized void init()  
2326            {
2327                    TradeHome tradeHome=null;
2328                    if (initialized) return;
2329                    if (Log.doTrace())
2330                            Log.trace("TradeDirect:init -- *** initializing");              
2331                    try
2332                    {
2333                            if (Log.doTrace())
2334                                    Log.trace("TradeDirect: init");                 
2335                            context = new InitialContext();
2336                            datasource = (DataSource) context.lookup(dsName);                       
2337            }
2338            catch (Exception e)
2339            {
2340                Log.error("TradeDirect:init -- error on JNDI lookups of DataSource -- TradeDirect will not work", e);
2341                return;
2342            }           
2343                            
2344                    try {
2345    
2346                 tradeHome = (TradeHome) ( javax.rmi.PortableRemoteObject.narrow(
2347                            context.lookup("java:comp/env/ejb/Trade"), TradeHome.class));
2348            }
2349            catch (Exception e)
2350            {
2351                Log.error("TradeDirect:init -- error on JNDI lookup of Trade Session Bean -- TradeDirect will not work", e);
2352                return;
2353            }           
2354            
2355            try
2356            {
2357                qConnFactory = (ConnectionFactory) context.lookup("java:comp/env/jms/QueueConnectionFactory");
2358            }
2359            catch (Exception e)
2360            {
2361                Log.error("TradeDirect:init  Unable to locate QueueConnectionFactory.\n\t -- Asynchronous mode will not work correctly and Quote Price change publishing will be disabled");
2362                publishQuotePriceChange = false;            
2363            }       
2364            
2365            try
2366            {
2367                queue = (Queue) context.lookup("java:comp/env/jms/TradeBrokerQueue");
2368            }
2369            catch (Exception e)
2370            {
2371                Log.error("TradeDirect:init  Unable to locate TradeBrokerQueue.\n\t -- Asynchronous mode will not work correctly and Quote Price change publishing will be disabled");
2372                publishQuotePriceChange = false;            
2373            }       
2374            
2375            try
2376            {
2377                tConnFactory = (ConnectionFactory) context.lookup("java:comp/env/jms/TopicConnectionFactory");
2378            }
2379            catch (Exception e)
2380            {
2381                Log.error("TradeDirect:init  Unable to locate TopicConnectionFactory.\n\t -- Asynchronous mode will not work correctly and Quote Price change publishing will be disabled");
2382                publishQuotePriceChange = false;            
2383            }
2384            
2385            try
2386            {
2387                streamerTopic = (Topic) context.lookup("java:comp/env/jms/TradeStreamerTopic");
2388            }
2389            catch (Exception e)
2390            {
2391                Log.error("TradeDirect:init  Unable to locate TradeStreamerTopic.\n\t -- Asynchronous mode will not work correctly and Quote Price change publishing will be disabled");
2392                publishQuotePriceChange = false;            
2393            }       
2394            
2395            
2396                    try
2397                    {
2398                            tradeEJB = (Trade) tradeHome.create();                                  
2399                    }
2400                    catch (Exception e)
2401                    {
2402                            Log.error("TradeDirect:init -- error looking up TradeEJB -- Asynchronous 1-phase will not work", e);
2403                    }                                       
2404                    if (Log.doTrace())              
2405                            Log.trace("TradeDirect:init -- +++ initialized");                       
2406                    
2407                    initialized = true;             
2408            }
2409            public static void destroy()    
2410            {
2411                    try
2412                    {
2413                            if (!initialized) return;
2414                            Log.trace("TradeDirect:destroy");
2415                    }
2416                    catch (Exception e)
2417                    {
2418                            Log.error("TradeDirect:destroy", e);
2419                    }
2420            }
2421    
2422    
2423            private static InitialContext context;
2424            private static ConnectionFactory qConnFactory;
2425            private static Queue queue;
2426            private static ConnectionFactory tConnFactory;
2427            private static Topic streamerTopic;
2428            private static Trade tradeEJB;
2429            private static boolean publishQuotePriceChange = true;
2430            /**
2431             * Gets the inGlobalTxn
2432             * @return Returns a boolean
2433             */
2434            private boolean getInGlobalTxn() {
2435                    return inGlobalTxn;
2436            }
2437            /**
2438             * Sets the inGlobalTxn
2439             * @param inGlobalTxn The inGlobalTxn to set
2440             */
2441            private void setInGlobalTxn(boolean inGlobalTxn) {
2442                    this.inGlobalTxn = inGlobalTxn;
2443            }
2444    
2445    }