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.ejb;
018    
019    import javax.ejb.*;
020    import javax.jms.*;
021    import javax.naming.*;
022    
023    import org.apache.geronimo.samples.daytrader.util.*;
024    
025    import java.math.BigDecimal;
026    import java.rmi.RemoteException;
027    import java.util.Collection;
028    import java.util.ArrayList;
029    import java.util.Iterator;
030    import org.apache.geronimo.samples.daytrader.*;
031    
032    public class TradeBean implements SessionBean {
033    
034            private SessionContext context = null;
035            private LocalAccountHome accountHome = null;
036            private LocalAccountProfileHome profileHome = null;
037            private LocalHoldingHome holdingHome = null;
038            private LocalQuoteHome quoteHome = null;
039            private LocalOrderHome orderHome = null;
040            private LocalKeySequenceHome keySequenceHome = null;
041            private LocalKeySequence keySequence;   
042            
043            private ConnectionFactory qConnFactory = null;
044            private Queue queue = null; 
045            private ConnectionFactory tConnFactory = null;
046            private Topic streamerTopic = null; 
047    
048            //Boolean to signify if the Order By clause is supported by the app server.
049            // This can be set to false by an env. variable
050            private boolean orderBySQLSupported = true;  
051            private boolean publishQuotePriceChange = true;  
052            private boolean updateQuotePrices = true;  
053       
054        private void queueOrderInternal(Integer orderID, boolean twoPhase)
055            throws javax.jms.JMSException
056        {
057                    if (Log.doTrace() ) Log.trace("TradeBean:queueOrderInternal", orderID);
058    
059                    Connection conn = null;
060                    Session sess = null;
061                    try
062                    {
063                            conn = qConnFactory.createConnection();                        
064                            sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
065                            MessageProducer msgProducer = sess.createProducer(queue);
066                            TextMessage   message = sess.createTextMessage();
067    
068                            message.setStringProperty("command", "neworder");
069                            message.setIntProperty("orderID", orderID.intValue());
070                            message.setBooleanProperty("twoPhase", twoPhase);
071                            message.setText("neworder: orderID="+orderID + " runtimeMode=EJB twoPhase="+twoPhase);
072                            message.setLongProperty("publishTime", System.currentTimeMillis());                                             
073    
074                            if (Log.doTrace()) Log.trace("TradeBean:queueOrder Sending message: " + message.getText());
075                            msgProducer.send(message);
076                    }
077                    catch (javax.jms.JMSException e)
078                    {
079                            throw e; // pass the exception back
080                    }
081                    
082                    finally {
083                            if (conn != null )
084                                    conn.close();
085                            if (sess != null)
086                                    sess.close();
087                    }
088            }
089            
090       /** 
091             * @see TradeServices#queueOrder(Integer)
092             */
093    
094            public void queueOrder(Integer orderID, boolean twoPhase)
095            throws Exception
096            {
097                    if (Log.doTrace() ) Log.trace("TradeBean:queueOrder", orderID, new Boolean(twoPhase));
098                    if (twoPhase)
099                            queueOrderInternal(orderID, true);
100                    else
101                    {
102                            // invoke the queueOrderOnePhase method -- which requires a new transaction
103                            // the queueOrder will run in it's own transaction thus not requiring a 
104                            // 2-phase commit
105                            ((Trade)context.getEJBObject()).queueOrderOnePhase(orderID);
106                    }
107            }
108            
109            
110       /** 
111             * @see TradeServices#queueOrderOnePhase(Integer)
112             * Queue the Order identified by orderID to be processed in a One Phase commit
113             * 
114             * In short, this method is deployed as TXN REQUIRES NEW to avoid a 
115             * 2-phase commit transaction across Entity and MDB access
116             * 
117             */
118    
119            public void queueOrderOnePhase(Integer orderID)
120                    throws RemoteException
121            {
122            try{
123                    if (Log.doTrace() ) Log.trace("TradeBean:queueOrderOnePhase", orderID);
124                    queueOrderInternal(orderID, false);
125            } catch (Exception e){
126                throw new RemoteException(e.getMessage(), e);
127            }
128            }
129            
130            class quotePriceComparator implements java.util.Comparator {
131                    public int compare(Object quote1, Object quote2)
132                    {
133                            double change1 = ((LocalQuote) quote1).getChange();
134                            double change2 = ((LocalQuote) quote2).getChange();
135                            return new Double(change2).compareTo(new Double(change1));
136                    }
137            }               
138    
139            public MarketSummaryDataBean getMarketSummary()
140            throws Exception {
141                    
142    
143                    MarketSummaryDataBean marketSummaryData = null;         
144                    try
145                    {
146                            if (Log.doTrace() ) {
147                                    Log.trace("TradeBean:getMarketSummary -- getting market summary");
148                            }
149    
150                            //Find Trade Stock Index Quotes (Top 100 quotes) 
151                            //ordered by their change in value
152                            Collection quotes=null;
153                            if ( orderBySQLSupported )
154                                    quotes = quoteHome.findTSIAQuotesOrderByChange();
155                            else
156                                    quotes = quoteHome.findTSIAQuotes();
157    
158                            //SORT by price change the collection of stocks if the AppServer
159                            //     does not support the "ORDER BY" SQL clause
160                            if (! orderBySQLSupported) {
161                                    //if (Log.doTrace()) 
162                                            Log.trace("TradeBean:getMarketSummary() -- Sorting TSIA quotes");
163                            ArrayList sortedQuotes = new ArrayList(quotes);
164                                java.util.Collections.sort(sortedQuotes, new quotePriceComparator());       
165                                quotes = sortedQuotes;
166                            }
167                        //SORT END 
168                        Object[] quoteArray = quotes.toArray();
169                        ArrayList topGainers = new ArrayList(5);
170                        ArrayList topLosers = new ArrayList(5);                 
171                            BigDecimal TSIA = FinancialUtils.ZERO;
172                            BigDecimal openTSIA = FinancialUtils.ZERO;                      
173                            double totalVolume = 0.0;
174    
175                       if (quoteArray.length > 5) {
176                                for (int i = 0; i < 5; i++)
177                                            topGainers.add(quoteArray[i]);
178                                    for (int i = quoteArray.length - 1; i >= quoteArray.length - 5; i--)
179                                            topLosers.add(quoteArray[i]);
180     
181                               for (int i = 0; i < quoteArray.length; i++) {
182                                    LocalQuote quote = (LocalQuote) quoteArray[i];
183                                    BigDecimal price = quote.getPrice();
184                                    BigDecimal open  = quote.getOpen();
185                                    double volume = quote.getVolume();
186                                    TSIA = TSIA.add(price);
187                                    openTSIA = openTSIA.add(open);                          
188                                    totalVolume += volume;
189                            }
190                                    TSIA = TSIA.divide(new BigDecimal(quoteArray.length),
191                                                    FinancialUtils.ROUND);
192                                    openTSIA = openTSIA.divide(new BigDecimal(quoteArray.length),
193                                                    FinancialUtils.ROUND);
194                            }
195                            /* This is an alternate approach using ejbSelect methods
196                             *   In this approach an ejbSelect is used to select only the 
197                             *   current price and open price values for the TSIA
198                                    LocalQuote quote = quoteHome.findOne();
199                                    BigDecimal TSIA = quote.getTSIA();
200                                    openTSIA = quote.getOpenTSIA();
201                                    Collection topGainers = quote.getTopGainers(5);
202                                    Collection topLosers = quote.getTopLosers(5);
203                                    LocalQuote quote = (LocalQuote)topGainers.iterator().next();
204                                    double volume = quote.getTotalVolume();                                                 
205                             *
206                             */                     
207    
208                            // Convert the collections of topGainer/topLoser entities                        
209                            // to collections of QuoteDataBeans
210                            Collection topGainersData = getDataBeansCollection(topGainers);
211                            Collection topLosersData = getDataBeansCollection(topLosers);                   
212    
213                            marketSummaryData = new MarketSummaryDataBean(TSIA, openTSIA, totalVolume, topGainersData, topLosersData);
214                    }
215                    catch (Exception e)
216                    {
217                            Log.error("TradeBean:getMarketSummary", e);
218                            throw new EJBException("TradeBean:getMarketSummary -- error ", e);
219                    }
220                    return marketSummaryData;
221            }
222    
223            public QuoteDataBean createQuote(String symbol, String companyName, BigDecimal price)
224                            throws CreateException, Exception
225            {
226                    try 
227                    {
228                            LocalQuote quote = quoteHome.create(symbol, companyName, price);
229                            QuoteDataBean quoteData = quote.getDataBean();
230                            if (Log.doTrace()) Log.trace("TradeBean:createQuote-->" + quoteData);
231                            return quoteData;
232                    }
233                    catch (Exception e)
234                    {
235                            Log.error("TradeBean:createQuote -- exception creating Quote", e);
236                            throw new EJBException(e);
237                    }
238            }
239    
240            public QuoteDataBean getQuote(String symbol)
241                    throws Exception
242            {
243    
244                    if (Log.doTrace()) Log.trace("TradeBean:getQuote", symbol);
245                    QuoteDataBean quoteData;
246                    try {
247                            LocalQuote quote = quoteHome.findByPrimaryKey(symbol);
248                            quoteData = quote.getDataBean();
249                    } catch (FinderException fe) {
250                                    //Cannot find quote for given symbol
251                                    Log.error("TradeBean:getQuote--> Symbol: " + symbol + " cannot be found");
252                                    BigDecimal z = new BigDecimal(0.0);
253                                    quoteData = new QuoteDataBean("Error: Symbol " + symbol + " not found", "", 0.0, z, z, z, z, 0.0 );
254                    }
255                    return quoteData;
256            }
257    
258            public Collection getAllQuotes() 
259                    throws Exception        
260            {
261                    if (Log.doTrace()) Log.trace("TradeBean:getAllQuotes");
262    
263                    Collection quoteBeans = new ArrayList();
264    
265                    try {
266                            Collection quotes = quoteHome.findAll();
267                            for (Iterator it = quotes.iterator(); it.hasNext(); ) {
268                                    LocalQuote quote = (LocalQuote)it.next();
269                                    quoteBeans.add(quote.getDataBean());
270                            }
271                    }
272                    catch (FinderException fe) {
273                            Log.error("TradeBean:getAllQuotes");
274                    }
275                    return quoteBeans;
276            }
277    
278            public QuoteDataBean updateQuotePriceVolume(String symbol, BigDecimal changeFactor, double sharesTraded) 
279                    throws Exception
280            {
281                    
282                    if ( TradeConfig.getUpdateQuotePrices() == false ) 
283                            return new QuoteDataBean();     
284                    
285                    if (Log.doTrace()) 
286                            Log.trace("TradeBean:updateQuote", symbol, changeFactor);       
287                    
288                    QuoteDataBean quoteData;
289                    try {
290                            LocalQuote quote = quoteHome.findByPrimaryKeyForUpdate(symbol);
291                            BigDecimal oldPrice = quote.getPrice();
292    
293                            if (quote.getPrice().equals(TradeConfig.PENNY_STOCK_PRICE)) {
294                                    changeFactor = TradeConfig.PENNY_STOCK_RECOVERY_MIRACLE_MULTIPLIER;
295                            }
296    
297                            BigDecimal newPrice = changeFactor.multiply(oldPrice).setScale(2, BigDecimal.ROUND_HALF_UP);
298    
299                            quote.updatePrice(newPrice);
300                            quote.addToVolume(sharesTraded);
301                            quoteData = quote.getDataBean();
302                            ((Trade)context.getEJBObject()).publishQuotePriceChange(quoteData, oldPrice, changeFactor, sharesTraded);
303    
304                    } catch (FinderException fe) {
305                            //Cannot find quote for given symbol
306                            Log.error("TradeBean:updateQuotePriceVolume--> Symbol: " + symbol + " cannot be found");
307                            quoteData = new QuoteDataBean("Error: Symbol " + symbol + " not found");
308                    }
309                    return quoteData;
310            }
311            
312            public void publishQuotePriceChange(QuoteDataBean quoteData, BigDecimal oldPrice, BigDecimal changeFactor, double sharesTraded)
313            throws RemoteException
314            {
315                    if ( publishQuotePriceChange == false)
316                            return;
317                    if (Log.doTrace())
318                            Log.trace("TradeBean:publishQuotePricePublishing -- quoteData = " + quoteData);         
319    
320                    Connection conn = null;
321                    Session sess = null;
322                    
323                    try
324                    {                       
325                            conn = tConnFactory.createConnection();                     
326                            sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
327                            MessageProducer msgProducer = sess.createProducer(streamerTopic);
328                            TextMessage message = sess.createTextMessage();
329    
330                            String command = "updateQuote";
331                            message.setStringProperty("command", command);
332                            message.setStringProperty("symbol",  quoteData.getSymbol() );
333                            message.setStringProperty("company", quoteData.getCompanyName() );              
334                            message.setStringProperty("price",   quoteData.getPrice().toString());
335                            message.setStringProperty("oldPrice",oldPrice.toString());              
336                            message.setStringProperty("open",    quoteData.getOpen().toString());
337                            message.setStringProperty("low",     quoteData.getLow().toString());
338                            message.setStringProperty("high",    quoteData.getHigh().toString());
339                            message.setDoubleProperty("volume",  quoteData.getVolume());            
340                                            
341                            message.setStringProperty("changeFactor", changeFactor.toString());             
342                            message.setDoubleProperty("sharesTraded", sharesTraded);                                
343                            message.setLongProperty("publishTime", System.currentTimeMillis());                                     
344                            message.setText("Update Stock price for " + quoteData.getSymbol() + " old price = " + oldPrice + " new price = " + quoteData.getPrice());
345    
346                            msgProducer.send(message);
347                    }
348                    catch (Exception e)
349                    {
350                            throw new RemoteException(e.getMessage(),e); // pass the exception back
351                    }       
352                    finally {       
353                try{
354                            if (conn != null)
355                                    conn.close();   
356                            if (sess != null)
357                            sess.close();           
358                }catch (Exception e){
359                    throw new RemoteException(e.getMessage(),e); // pass the exception back
360                }
361                    }
362            }       
363    
364            public OrderDataBean buy(String userID, String symbol, double quantity, int orderProcessingMode)
365            throws Exception 
366            {
367    
368                    LocalOrder order=null;
369                    BigDecimal total;               
370                    try {
371                            if (Log.doTrace()) 
372                                    Log.trace("TradeBean:buy", userID, symbol, new Double(quantity), new Integer(orderProcessingMode));                                     
373                    /*  The following commented code shows alternative forms of the finder needed for this
374                     *  method
375                     *  The first alternative requires a 2-table join. Some database cannot allocate an Update
376                     *  Lock on a join select.
377                     * 
378                     *  The second alternative shows the finder being executed without allocation an update
379                     *  lock on the row. Normally, an update lock would not be necessary, but is required if
380                     *  the same user logs in multiple times to avoid a deadlock situation.
381                     * 
382                     *  The third alternative runs the finder and allocates an update lock on the row(s)
383                     *                      
384                            LocalAccount account = accountHome.findByUserIDForUpdate(userID);       
385     
386                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKey(userID)).getAccountForUpdate();
387                     */
388                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(userID)).getAccountForUpdate();
389    
390                            LocalQuote quote = quoteHome.findByPrimaryKey(symbol);
391                            LocalHolding holding = null;  //The holding will be created by this buy order
392                            Integer orderID  = keySequence.getNextID("order");
393    
394                            order = createOrder(orderID, account, quote, holding, "buy", quantity);
395    
396                            //UPDATE - account should be credited during completeOrder
397                            BigDecimal price = quote.getPrice();
398                            BigDecimal orderFee = order.getOrderFee();
399                            BigDecimal balance = account.getBalance();
400                            total   = (new BigDecimal(quantity).multiply(price)).add(orderFee);
401                            account.setBalance(balance.subtract(total));                    
402                            
403                            if (orderProcessingMode == TradeConfig.SYNCH) 
404                                    completeOrderInternal(order.getOrderID());
405                            else if (orderProcessingMode == TradeConfig.ASYNCH)
406                                    // Invoke the queueOrderOnePhase method w/ TXN requires new attribute
407                                    // to side-step a 2-phase commit across DB and JMS access
408                                    queueOrder(order.getOrderID(), false);
409                            else //TradeConfig.ASYNC_2PHASE
410                                    queueOrder(order.getOrderID(), true);
411                    }
412                    catch (Exception e)
413                    {
414                            Log.error("TradeBean:buy("+userID+","+symbol+","+quantity+") --> failed", e);
415                            /* On exception - cancel the order */
416                            if (order != null) order.cancel();
417                            throw new EJBException(e);
418                    }       
419                    return order.getDataBean();
420            }
421    
422            public OrderDataBean sell(String userID, Integer holdingID, int orderProcessingMode) 
423            throws Exception 
424            {
425                    
426                    LocalOrder order=null;
427                    BigDecimal total;               
428                    try {
429                            if (Log.doTrace()) 
430                                    Log.trace("TradeBean:sell", userID, holdingID, new Integer(orderProcessingMode));                                       
431                            
432                            /* Some databases cannot allocate an update lock on a JOIN
433                             * use the second approach below to acquire update lock
434                            LocalAccount account = accountHome.findByUserIDForUpdate(userID);
435                            */
436                     
437                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(userID)).getAccountForUpdate();
438                            LocalHolding holding;
439                            try {
440                                    holding = holdingHome.findByPrimaryKeyForUpdate(holdingID);
441                            }
442                            catch (ObjectNotFoundException oe)
443                            {
444                                    Log.error("TradeBean:sell User " + userID + " attempted to sell holding " + holdingID + " which has already been sold");
445                                    OrderDataBean orderData = new OrderDataBean();
446                                    orderData.setOrderStatus("cancelled");
447                                    return orderData;
448                            }
449                            LocalQuote   quote = holding.getQuote();
450                            double           quantity = holding.getQuantity();
451                            Integer orderID = keySequence.getNextID("order");
452                            order = createOrder(orderID, account, quote, holding, "sell", quantity);
453    
454                            //UPDATE the holding purchase data to signify this holding is "inflight" to be sold
455                            //    -- could add a new holdingStatus attribute to holdingEJB
456                            holding.setPurchaseDate(new java.sql.Timestamp(0));
457                            
458                            //UPDATE - account should be credited during completeOrder
459                            BigDecimal price = quote.getPrice();
460                            BigDecimal orderFee = order.getOrderFee();
461                            BigDecimal balance = account.getBalance();      
462                            total   = (new BigDecimal(quantity).multiply(price)).subtract(orderFee);                                
463                            account.setBalance(balance.add(total));
464                            
465                            if (orderProcessingMode == TradeConfig.SYNCH) 
466                                    completeOrderInternal(order.getOrderID());
467                            else if (orderProcessingMode == TradeConfig.ASYNCH)
468                                    queueOrder(order.getOrderID(), false);
469                            else //TradeConfig.ASYNC_2PHASE
470                                    queueOrder(order.getOrderID(), true);
471    
472                    }
473                    catch (Exception e)
474                    {               
475                            Log.error("TradeBean:sell("+userID+","+holdingID+") --> failed", e);
476                            if (order != null) order.cancel();
477                            //UPDATE - handle all exceptions like:
478                            throw new EJBException("TradeBean:sell("+userID+","+holdingID+")",e);   
479                    }
480                    return order.getDataBean();
481            }
482    
483    
484            public Collection getOrders(String userID) 
485                    throws FinderException, Exception
486            {
487                    
488                    if (Log.doTrace()) 
489                            Log.trace("TradeBean:getOrders", userID);
490    
491                    /*  The following commented code shows alternative forms of the finder needed for this
492                     *  method
493                     *  The first alternative requires a 2-table join. Some database cannot allocate an Update
494                     *  Lock on a join select.
495                     * 
496                     *  The second alternative shows the finder being executed without allocation an update
497                     *  lock on the row. Normally, an update lock would not be necessary, but is required if
498                     *  the same user logs in multiple times to avoid a deadlock situation.
499                     * 
500                     *  The third alternative runs the finder and allocates an update lock on the row(s)
501                     *                                      
502                    
503                            Collection orders = accountHome.findByUserID(userID).getOrders();
504                            
505                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKey(userID)).getAccountForUpdate();
506                     */
507                    LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(userID)).getAccountForUpdate();
508                    Collection orders = account.getOrders();
509    
510                    ArrayList dataBeans = new ArrayList();
511                    if ( orders == null ) return dataBeans;
512                    
513                    Iterator it = orders.iterator();
514                    //TODO: return top 5 orders for now -- next version will add a getAllOrders method
515                    //      also need to get orders sorted by order id descending
516                    int i=0;
517                    while ( (it.hasNext()) && (i++ < 5)) 
518                            dataBeans.add(((LocalOrder) it.next()).getDataBean());
519                    
520                    return dataBeans;
521            }
522    
523            public Collection getClosedOrders(String userID) 
524                    throws FinderException, Exception
525            {
526                    if (Log.doTrace()) 
527                            Log.trace("TradeBean:getClosedOrders", userID);
528    
529                    ArrayList dataBeans = new ArrayList();          
530                    try {
531    
532                    /*  The following commented code shows alternative forms of the finder needed for this
533                     *  method
534                     *  The first alternative requires a 2-table join. Some database cannot allocate an Update
535                     *  Lock on a join select.
536                     * 
537                     *  The second alternative shows the finder being executed without allocation an update
538                     *  lock on the row. Normally, an update lock would not be necessary, but is required if
539                     *  the same user logs in multiple times to avoid a deadlock situation.
540                     * 
541                     *  The third alternative runs the finder and allocates an update lock on the row(s)
542                     *                      
543                            Collection orders = orderHome.findClosedOrdersForUpdate(userID);                
544                     *
545                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKey(userID)).getAccount();                                                       
546                     */
547    
548                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(userID)).getAccountForUpdate();                                                     
549                            //Get the primary keys for all the closed Orders for this account.
550                            Collection ordersKeys = account.getClosedOrders();
551                            if ( ordersKeys == null ) return dataBeans;
552                    
553                            Iterator it = ordersKeys.iterator();
554                            while (it.hasNext())
555                            {
556                                    Integer orderKey = (Integer) it.next();
557                                    LocalOrder order = (LocalOrder) orderHome.findByPrimaryKeyForUpdate(orderKey);
558                                    //Complete the order 
559                                    order.setOrderStatus("completed");
560                                    dataBeans.add(order.getDataBean());
561                            }
562                            
563                    }
564                    catch (Exception e)
565                    {
566                            Log.error("TradeBean.getClosedOrders", e);
567                            throw new EJBException("TradeBean.getClosedOrders - error", e);
568                    }
569                    return dataBeans;
570            }
571            
572    
573            public OrderDataBean completeOrder(Integer orderID, boolean twoPhase)
574            throws Exception {
575                    if (Log.doTrace()) Log.trace("TradeBean:completeOrder", orderID + " twoPhase="+twoPhase);
576                    if (twoPhase)
577                            return completeOrderInternal(orderID);
578                    else
579                    {
580                            // invoke the completeOrderOnePhase -- which requires a new transaction
581                            // the completeOrder will run in it's own transaction thus not requiring a 
582                            // 2-phase commit
583                            return ((Trade)context.getEJBObject()).completeOrderOnePhase(orderID);
584                    }
585            }
586            
587            //completeOrderOnePhase method is deployed w/ TXN_REQUIRES_NEW
588            //thus the completeOrder call from the MDB should not require a 2-phase commit
589            public OrderDataBean completeOrderOnePhase(Integer orderID)
590            throws RemoteException {
591            try{
592                    if (Log.doTrace()) Log.trace("TradeBean:completeOrderOnePhase", orderID);               
593                    return completeOrderInternal(orderID);
594            }catch (Exception e){
595                throw new RemoteException(e.getMessage(),e);
596            }
597            }
598    
599            private OrderDataBean completeOrderInternal(Integer orderID) 
600                            throws Exception
601            {
602    
603                    LocalOrder order = orderHome.findByPrimaryKeyForUpdate(orderID);
604                    
605                    if (order == null)
606                    {
607                            Log.error("TradeBean:completeOrderInternal  -- Unable to find Order " + orderID + " FBPK returned " + order);
608                            order.cancel();                 
609                            return order.getDataBean();
610                    }
611    
612                    String orderType = order.getOrderType();
613                    String orderStatus = order.getOrderStatus();
614    
615                    if (order.isCompleted())
616                            throw new EJBException("Error: attempt to complete Order that is already completed\n" + order);
617    
618                    LocalAccount account = order.getAccount();
619                    LocalQuote     quote = order.getQuote();
620                    LocalHolding holding = order.getHoldingForUpdate();
621                    BigDecimal     price = order.getPrice();
622                    double      quantity = order.getQuantity();
623                    BigDecimal  orderFee = order.getOrderFee();
624    
625                    BigDecimal balance = account.getBalance();
626    
627                    /* 
628                     *      getProfile is marked as Pess. Update to get a DB lock
629                     * Here we invoke getProfileForRead which is deployed to not
630                     * lock the DB (Pess. Read)
631                     */      
632                     String userID = account.getProfile().getUserID();
633                            
634                    /*       
635                     * total = (quantity * purchasePrice) + orderFee
636                     */
637    
638                            
639                    if (Log.doTrace()) Log.trace(
640                                            "TradeBeanInternal:completeOrder--> Completing Order " + order.getOrderID()
641                                             + "\n\t Order info: "   +   order
642                                             + "\n\t Account info: " + account
643                                             + "\n\t Quote info: "   +   quote
644                                             + "\n\t Holding info: " + holding);
645                            
646    
647                    if (order.isBuy()) {
648                            /* Complete a Buy operation
649                             *      - create a new Holding for the Account
650                             *      - deduct the Order cost from the Account balance
651                             */
652    
653                            LocalHolding newHolding = createHolding(account, quote, quantity, price);
654                            order.setHolding(newHolding);
655                    }
656                    
657                    if (order.isSell()) {
658                            /* Complete a Sell operation
659                             *      - remove the Holding from the Account
660                             *      - deposit the Order proceeds to the Account balance
661                             */
662                            if ( holding == null )
663                            {
664                                    Log.error("TradeBean:completeOrderInternal -- Unable to sell order " + order.getOrderID() + " holding already sold");
665                                    order.cancel();
666                                    return order.getDataBean();
667                            }
668                            else
669                            {       
670                                    holding.remove();
671                                    holding = null;
672                            }
673    
674                            // This is managed by the container
675                            // order.setHolding(null);
676    
677                    }
678                    order.setOrderStatus("closed");
679    
680                    order.setCompletionDate(new java.sql.Timestamp(System.currentTimeMillis()));
681                    
682                    if (Log.doTrace()) Log.trace(
683                                            "TradeBean:completeOrder--> Completed Order " + order.getOrderID()
684                                             + "\n\t Order info: "   +   order
685                                             + "\n\t Account info: " + account
686                                             + "\n\t Quote info: "   +   quote
687                                             + "\n\t Holding info: " + holding);
688    
689                    BigDecimal priceChangeFactor = TradeConfig.getRandomPriceChangeFactor();
690                    if(Log.doTrace())
691                            Log.trace("Calling TradeAction:orderCompleted from Session EJB using Session Object");          
692                            //FUTURE All getEJBObjects could be local -- need to add local I/F
693    
694                    TradeServices trade = (TradeServices)context.getEJBObject();
695                    TradeAction tradeAction = new TradeAction(trade);
696    
697                    //signify this order for user userID is complete
698                    tradeAction.orderCompleted(userID, orderID);
699                    return order.getDataBean();
700            }
701            
702            
703            //These methods are used to provide the 1-phase commit runtime option for TradeDirect
704            // Basically these methods are deployed as txn requires new and invoke TradeDirect methods
705            // There is no mechanism outside of EJB to start a new transaction
706        public OrderDataBean completeOrderOnePhaseDirect(Integer orderID)
707        throws RemoteException {
708            try{
709            if (Log.doTrace())
710                    Log.trace("TradeBean:completeOrderOnePhaseDirect -- completing order by calling TradeDirect orderID=" +orderID);
711                return (new org.apache.geronimo.samples.daytrader.direct.TradeDirect()).completeOrderOnePhase(orderID);
712            } catch (Exception e){
713                throw new RemoteException(e.getMessage(),e);
714            }
715        }
716            public void cancelOrderOnePhaseDirect(Integer orderID) 
717            throws RemoteException {
718            try{
719            if (Log.doTrace())
720                    Log.trace("TradeBean:cancelOrderOnePhaseDirect -- cancelling order by calling TradeDirect orderID=" +orderID);
721                    (new org.apache.geronimo.samples.daytrader.direct.TradeDirect()).cancelOrderOnePhase(orderID);
722            } catch(Exception e){
723                throw new RemoteException(e.getMessage(),e);
724            }
725            }
726            
727            
728            public void cancelOrder(Integer orderID, boolean twoPhase)
729            throws Exception {
730                    if (Log.doTrace()) Log.trace("TradeBean:cancelOrder", orderID + " twoPhase="+twoPhase);
731                    if (twoPhase)
732                            cancelOrderInternal(orderID);
733                    else
734                    {
735                            // invoke the cancelOrderOnePhase -- which requires a new transaction
736                            // the completeOrder will run in it's own transaction thus not requiring a 
737                            // 2-phase commit
738                            ((Trade)context.getEJBObject()).cancelOrderOnePhase(orderID);
739                    }
740            }
741    
742            //cancelOrderOnePhase method is deployed w/ TXN_REQUIRES_NEW
743            //thus the completeOrder call from the MDB should not require a 2-phase commit
744            public void cancelOrderOnePhase(Integer orderID)
745            throws RemoteException {
746            try{
747                    if (Log.doTrace()) Log.trace("TradeBean:cancelOrderOnePhase", orderID);         
748                    cancelOrderInternal(orderID);
749            } catch (Exception e){
750                throw new RemoteException(e.getMessage(),e);
751            }
752            }
753            
754            
755            private void cancelOrderInternal(Integer orderID)
756            throws Exception
757            {
758                    LocalOrder order = orderHome.findByPrimaryKeyForUpdate(orderID);
759                    order.cancel();
760            }
761            
762                    
763            public void orderCompleted(String userID, Integer orderID) 
764            throws Exception
765            {
766                    throw new UnsupportedOperationException("TradeBean:orderCompleted method not supported");
767            }
768            public LocalHolding createHolding(
769                    LocalAccount account,
770                    LocalQuote quote,
771                    double quantity,
772                    BigDecimal purchasePrice) 
773                    throws Exception                
774            {
775                    LocalHolding newHolding = null;
776                    Integer holdingID = null;
777                    try {
778    
779                    if (Log.doTrace())
780                            Log.trace("TradeBean:createHolding");
781    
782                            holdingID = keySequence.getNextID("holding");
783                            newHolding =
784                                    holdingHome.create(holdingID, account, quote, quantity, purchasePrice);
785                    } catch (Exception e) {
786                            String error = "Failed to create Holding for account: " + account.getAccountID() 
787                                                            + " with quote: " + quote.getSymbol() 
788                                                            + " holdingID: " + holdingID 
789                                                            + " quantity: " + quantity + "\n";
790                            Log.error(e, error );
791                            throw new EJBException(error,e);
792                    }
793                    return newHolding;
794            }
795    
796            public Collection getHoldings(String userID) 
797                    throws FinderException, Exception
798            {
799                    if (Log.doTrace())
800                            Log.trace("TradeBean:getHoldings", userID);
801                    Collection holdings = holdingHome.findByUserID(userID);
802                    if (Log.doTrace())
803                            Log.trace("Got holdings collection size="+holdings.size());             
804                    ArrayList dataBeans = new ArrayList();
805                    if ( holdings == null ) return dataBeans;
806            
807                    Iterator it = holdings.iterator();
808                    while (it.hasNext()) {
809                            HoldingDataBean holdingData = ((LocalHolding) it.next()).getDataBean();
810                            dataBeans.add(holdingData);
811                    }
812                    return dataBeans;
813            }
814            
815            public HoldingDataBean getHolding(Integer holdingID) 
816                    throws FinderException, Exception
817            {
818                    if (Log.doTrace())
819                            Log.trace("TradeBean:getHolding", holdingID);
820                    LocalHolding holding = holdingHome.findByPrimaryKey(holdingID);
821                    HoldingDataBean holdingData = holding.getDataBean();            
822                    if (Log.doTrace())
823                            Log.trace("TradeBean:getHolding " + holdingData);               
824                    return holdingData;
825            }
826    
827    
828    
829            public LocalOrder createOrder(
830                    int orderID,
831                    LocalAccount account,
832                    LocalQuote quote,
833                    LocalHolding holding,
834                    String orderType,
835                    double quantity)
836            throws Exception {
837                    try
838                    {
839                            return createOrder(new Integer(orderID), account, quote, holding, orderType, quantity);
840                    }
841                    catch(Exception e)
842                    {
843                            Log.error("TradeBean:createOrder -- failed to create Order", e);
844                            throw new EJBException("TradeBean:createOrder -- failed to create Order", e);
845                    }
846            }
847    
848            public LocalOrder createOrder(
849                    Integer orderID,
850                    LocalAccount account,
851                    LocalQuote quote,
852                    LocalHolding holding,
853                    String orderType,
854                    double quantity)
855            throws CreateException, Exception {
856    
857                    LocalOrder order = null;
858                    
859                    if (Log.doTrace() )
860                            Log.trace(
861                            "TradeBean:createOrder(orderID="
862                                    + orderID
863                                    + " account="
864                                    + ((account == null) ? null : account.getPrimaryKey())
865                                    + " quote="
866                                    + ((quote == null) ? null : quote.getPrimaryKey())
867                                    + " orderType="
868                                    + orderType
869                                    + " quantity="
870                                    + quantity);
871                    try
872                    {                       
873                            order = orderHome.create(orderID, account, quote, holding, orderType, quantity);
874                    }
875                    catch(Exception e)
876                    {
877                            Log.error("TradeBean:createOrder -- failed to create Order", e);
878                            throw new EJBException("TradeBean:createOrder -- failed to create Order", e);
879                    }               
880                    return order;
881            }
882    
883            public AccountDataBean login(String userID, String password)
884            throws FinderException, Exception {
885                    
886                    /*  The following commented code shows alternative forms of the finder needed for this
887                     *  method
888                     *  The first alternative requires a 2-table join. Some database cannot allocate an Update
889                     *  Lock on a join select.
890                     * 
891                     *  The second alternative shows the finder being executed without allocation an update
892                     *  lock on the row. Normally, an update lock would not be necessary, but is required if
893                     *  the same user logs in multiple times to avoid a deadlock situation.
894                     * 
895                     *  The third alternative runs the finder and allocates an update lock on the row(s)
896                     *
897                            LocalAccount account = accountHome.findByUserIDForUpdate(userID);
898                     
899                        LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKey(userID)).getAccountForUpdate();
900                     */
901                     LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(userID)).getAccountForUpdate();
902                     
903                    if (Log.doTrace())
904                            Log.trace("TradeBean:login", userID, password);
905                    account.login(password);
906                    AccountDataBean accountData = account.getDataBean();
907                    if (Log.doTrace())
908                            Log.trace("TradeBean:login(" + userID + "," + password + ") success" + accountData);
909                    return accountData;
910            }
911    
912            public void logout(String userID)
913            throws FinderException, Exception {
914                    if (Log.doTrace())
915                            Log.trace("TradeBean:logout", userID);
916                            
917                    /*  The following commented code shows alternative forms of the finder needed for this
918                     *  method
919                     *  The first alternative requires a 2-table join. Some database cannot allocate an Update
920                     *  Lock on a join select.
921                     * 
922                     *  The second alternative shows the finder being executed without allocation an update
923                     *  lock on the row. Normally, an update lock would not be necessary, but is required if
924                     *  the same user logs in multiple times to avoid a deadlock situation.
925                     * 
926                     *  The third alternative runs the finder and allocates an update lock on the row(s)
927                     
928                     *      LocalAccount account = accountHome.findByUserIDForUpdate(userID);
929                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKey(userID)).getAccountForUpdate();
930                     *
931                     */
932                    LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(userID)).getAccountForUpdate();
933                    
934                    
935                    if (Log.doTrace()) Log.trace("TradeBean:logout(" + userID + ") success");
936                    account.logout();
937            }
938    
939            public AccountDataBean register(
940                    String userID,
941                    String password,
942                    String fullname,
943                    String address,
944                    String email,
945                    String creditcard,
946                    BigDecimal openBalance)
947                    throws CreateException, Exception {
948    
949                    LocalAccount account = null;
950    
951                    try {
952                    if (Log.doTrace())
953                            Log.trace("TradeBean:register", userID, password, fullname, address, email, creditcard, openBalance);
954                            
955                            Integer accountID = keySequence.getNextID("account");
956                            account =
957                                    accountHome.create(
958                                            accountID,
959                                            userID,
960                                            password,
961                                            openBalance,
962                                            fullname,
963                                            address,
964                                            email,
965                                            creditcard);
966                    }
967                    catch (Exception e)
968                    {
969                                    Log.error("Failed to register new Account\n" + e);
970                                    throw new EJBException("Failed to register new Account\n", e);
971                    }       
972                    AccountDataBean accountData = account.getDataBean();            
973                    return accountData;
974            }
975    
976            public AccountDataBean getAccountData(String userID)
977            throws FinderException, RemoteException {
978    
979                    if (Log.doTrace())
980                            Log.trace("TradeBean:getAccountData", userID);
981    
982                    /*  The following commented code shows alternative forms of the finder needed for this
983                     *  method
984                     *  The first alternative requires a 2-table join. Some database cannot allocate an Update
985                     *  Lock on a join select.
986                     * 
987                     *  The second alternative shows the finder being executed without allocation an update
988                     *  lock on the row. Normally, an update lock would not be necessary, but is required if
989                     *  the same user logs in multiple times to avoid a deadlock situation.
990                     * 
991                     *  The third alternative runs the finder and allocates an update lock on the row(s)
992                     *                                      
993                            LocalAccount account = accountHome.findByUserID(userID);
994                            
995                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKey(userID)).getAccountForUpdate();
996                     */
997                    LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(userID)).getAccountForUpdate();
998    
999                    AccountDataBean accountData = account.getDataBean();
1000                    return accountData;
1001            }
1002            public AccountProfileDataBean getAccountProfileData(String userID)
1003            throws FinderException, Exception {
1004                    if (Log.doTrace())
1005                            Log.trace("TradeBean:getAccountProfileData", userID);
1006    
1007                    /*  The following commented code shows alternative forms of the finder needed for this
1008                     *  method
1009                     *  The first alternative requires a 2-table join. Some database cannot allocate an Update
1010                     *  Lock on a join select.
1011                     * 
1012                     *  The second alternative shows the finder being executed without allocation an update
1013                     *  lock on the row. Normally, an update lock would not be necessary, but is required if
1014                     *  the same user logs in multiple times to avoid a deadlock situation.
1015                     * 
1016                     *  The third alternative runs the finder and allocates an update lock on the row(s)
1017                     *                                      
1018                            LocalAccount account = accountHome.findByUserID(userID);
1019                            
1020                            LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKey(userID)).getAccountForUpdate();
1021                     */
1022                    LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(userID)).getAccountForUpdate();
1023    
1024                    AccountProfileDataBean accountProfileData = account.getProfileDataBean();
1025                    return accountProfileData;
1026            }
1027    
1028            public AccountProfileDataBean updateAccountProfile(AccountProfileDataBean accountProfileData)
1029            throws FinderException, Exception {
1030                    
1031                    if (Log.doTrace())
1032                            Log.trace("TradeBean:updateAccountProfileData", accountProfileData);
1033                    
1034                    LocalAccount account = ((LocalAccountProfile) profileHome.findByPrimaryKeyForUpdate(accountProfileData.getUserID())).getAccountForUpdate();
1035    
1036                    accountProfileData =
1037                            account.updateAccountProfile(accountProfileData);
1038                    return accountProfileData;
1039            }
1040            
1041            public RunStatsDataBean resetTrade(boolean deleteAll)
1042            throws Exception
1043            {
1044                    if (Log.doTrace())
1045                            Log.trace("TradeBean:resetTrade", new Boolean(deleteAll));
1046    
1047                    //Clear MDB Statistics          
1048                    MDBStats.getInstance().reset();
1049                    // Reset Trade
1050                    return new org.apache.geronimo.samples.daytrader.direct.TradeDirect().resetTrade(deleteAll);
1051            }
1052    
1053            private Collection getDataBeansCollection(Collection entities)
1054            {
1055                    ArrayList dataBeans = new ArrayList();
1056            
1057                    if ( (entities == null) || (entities.size()<= 0) )
1058                    return dataBeans;
1059    
1060                    Iterator it = entities.iterator();
1061                    while (it.hasNext()) {
1062                            LocalQuote entity = (LocalQuote) it.next();
1063                            Object o = (Object)entity.getDataBean();
1064                            dataBeans.add(o);
1065                    }
1066                    return dataBeans;
1067            }
1068    
1069            /**
1070             * provides a simple session method with no database access to test performance of a simple
1071             * path through a stateless session 
1072             * @param investment amount
1073             * @param NetValue current value
1074             * @return return on investment as a percentage
1075             */
1076            public double investmentReturn(double investment, double NetValue)
1077                    throws RemoteException
1078            {
1079                    if (Log.doTrace())
1080                            Log.trace("TradeBean:investmentReturn");
1081                    
1082                    double diff = NetValue - investment;
1083                    double ir = diff / investment;
1084                    return ir;
1085    
1086            }
1087            
1088            /**
1089             * This method provides a ping test for a 2-phase commit operation
1090             * 
1091             * @param symbol to lookup
1092             * @return quoteData after sending JMS message
1093             */     
1094            public QuoteDataBean pingTwoPhase(String symbol)
1095            throws RemoteException
1096            {
1097            try{
1098                    if (Log.doTrace()) Log.trace("TradeBean:pingTwoPhase", symbol);
1099                    QuoteDataBean quoteData=null;
1100                    Connection conn = null;
1101                    Session sess = null;            
1102                    try {
1103                            
1104                            //Get a Quote and send a JMS message in a 2-phase commit
1105                            LocalQuote quote = quoteHome.findByPrimaryKey(symbol);
1106                            quoteData = quote.getDataBean();
1107    
1108                            conn = qConnFactory.createConnection();                        
1109                            sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
1110                            MessageProducer msgProducer = sess.createProducer(queue);
1111                            TextMessage   message = sess.createTextMessage();
1112    
1113                            String command= "ping";
1114                            message.setStringProperty("command", command);
1115                            message.setLongProperty("publishTime", System.currentTimeMillis());                     
1116                            message.setText("Ping message for queue java:comp/env/jms/TradeBrokerQueue sent from TradeSessionEJB:pingTwoPhase at " + new java.util.Date());
1117    
1118                            msgProducer.send(message);      
1119                    } 
1120                    catch (Exception e) {
1121                            Log.error("TradeBean:pingTwoPhase -- exception caught",e);
1122                    }
1123    
1124                    finally {
1125                            if (conn != null)
1126                                    conn.close();   
1127                            if (sess != null)
1128                                    sess.close();
1129                    }                       
1130                    
1131                    return quoteData;
1132            } catch (Exception e){
1133                throw new RemoteException(e.getMessage(),e);
1134            }
1135            }       
1136    
1137    
1138        /* Required javax.ejb.SessionBean interface methods */
1139    
1140            public TradeBean() {
1141            }
1142    
1143            private static boolean warnJMSFailure = true;
1144            public void ejbCreate() throws CreateException {
1145                    try {
1146    
1147                            if (Log.doTrace())
1148                                    Log.trace("TradeBean:ejbCreate  -- JNDI lookups of EJB and JMS resources");
1149    
1150                            InitialContext ic = new InitialContext();
1151                            quoteHome               = (LocalQuoteHome)   ic.lookup("java:comp/env/ejb/Quote");
1152                            accountHome     = (LocalAccountHome) ic.lookup("java:comp/env/ejb/Account");
1153                            profileHome     = (LocalAccountProfileHome) ic.lookup("java:comp/env/ejb/AccountProfile");
1154                            holdingHome     = (LocalHoldingHome) ic.lookup("java:comp/env/ejb/Holding");
1155                            orderHome               = (LocalOrderHome)   ic.lookup("java:comp/env/ejb/Order");
1156                            keySequenceHome = (LocalKeySequenceHome) ic.lookup("java:comp/env/ejb/KeySequence");                    
1157    
1158                            orderBySQLSupported = ( (Boolean) ic.lookup("java:comp/env/orderBySQLSupported") ).booleanValue();
1159                            publishQuotePriceChange  = ( (Boolean) ic.lookup("java:comp/env/publishQuotePriceChange") ).booleanValue();
1160                            updateQuotePrices  = ( (Boolean) ic.lookup("java:comp/env/updateQuotePrices") ).booleanValue();
1161                            TradeConfig.setUpdateQuotePrices(updateQuotePrices);
1162    
1163                            try
1164                            {
1165                                    qConnFactory = (ConnectionFactory) ic.lookup("java:comp/env/jms/QueueConnectionFactory");
1166                     tConnFactory = (ConnectionFactory) ic.lookup("java:comp/env/jms/TopicConnectionFactory");
1167                                    streamerTopic = (Topic) ic.lookup("java:comp/env/jms/TradeStreamerTopic");
1168                     queue = (Queue) ic.lookup("java:comp/env/jms/TradeBrokerQueue");
1169                            }
1170                            catch (Exception e)
1171                            {
1172                                    if (warnJMSFailure == true)
1173                                    {
1174                                            warnJMSFailure = false;
1175                                            Log.error("TradeBean:ejbCreate  Unable to lookup JMS Resources\n\t -- Asynchronous mode will not work correctly and Quote Price change publishing will be disabled", e);
1176                                    }                               
1177                                    publishQuotePriceChange = false;                        
1178                            }               
1179                            
1180                    } catch (Exception e) {
1181                            Log.error("TradeBean:ejbCreate: Lookup of Local Entity Homes Failed\n" + e);
1182                            e.printStackTrace();
1183                            //UPDATE
1184                            //throw new CreateException(e.toString());
1185                    }
1186    
1187                    if ((quoteHome  == null) ||
1188                            (     accountHome       == null) ||
1189                            (     holdingHome       == null) ||
1190                            (       orderHome       == null) ||
1191                            ( keySequenceHome       == null) //||                                   
1192    //                      (    qConnFactory       == null) ||
1193    //                      (           queue       == null) ||
1194    //                      (    tConnFactory       == null) ||
1195    //                      (   streamerTopic       == null) ||
1196                            )
1197                            {
1198                                    String error = "TradeBean:ejbCreate()  JNDI lookup of Trade resource failed\n" +
1199                                            "\n\t quoteHome="+quoteHome+
1200                                            "\n\t accountHome="+ accountHome+
1201                                            "\n\t holdingHome="+ holdingHome+
1202                                            "\n\t orderHome="+ orderHome+
1203                                            "\n\t qConnFactory="+ qConnFactory+
1204                                            "\n\t queue="+ queue+
1205                                            "\n\t tConnFactory="+ tConnFactory+
1206                                            "\n\t streamerTopic="+ streamerTopic;
1207                                    Log.error(error);
1208                                    //UPDATE
1209                                    //throw new EJBException(error);
1210                            }
1211                    keySequence = keySequenceHome.create();
1212            }
1213    
1214            public void ejbRemove() 
1215            {
1216                    try
1217                    {
1218                            if (Log.doTrace())
1219                                    Log.trace("TradeBean:ejbRemove");
1220                    }
1221                    catch (Exception e)
1222                    {
1223                            Log.error(e,"Unable to close Queue or Topic connection on Session EJB remove");
1224                    }
1225            }
1226            public void ejbActivate() {
1227            }
1228            public void ejbPassivate() {
1229            }
1230    
1231            public void setSessionContext(SessionContext sc) {
1232                    context = sc;
1233            }
1234    }