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; 018 019 import java.math.BigDecimal; 020 import java.rmi.RemoteException; 021 import java.util.Collection; 022 023 import javax.naming.InitialContext; 024 025 import org.apache.geronimo.samples.daytrader.direct.TradeDirect; 026 import org.apache.geronimo.samples.daytrader.ejb.TradeHome; 027 import org.apache.geronimo.samples.daytrader.session.TradeJDBCHome; 028 import org.apache.geronimo.samples.daytrader.util.FinancialUtils; 029 import org.apache.geronimo.samples.daytrader.util.Log; 030 031 /** 032 * The TradeAction class provides the generic client side access to each of the 033 * Trade brokerage user operations. These include login, logout, buy, sell, 034 * getQuote, etc. The TradeAction class does not handle user interface 035 * processing and should be used by a class that is UI specific. For example, 036 * {trade_client.TradeServletAction}manages a web interface to Trade, 037 * making calls to TradeAction methods to actually performance each operation. 038 */ 039 public class TradeAction implements TradeServices { 040 private TradeServices trade = null; 041 private static TradeHome tradeHome = null; 042 private static TradeJDBCHome tradeJDBCHome = null; 043 private static TradeHome tradeHomeJPA = null; 044 045 046 public TradeAction() { 047 if (Log.doTrace()) 048 Log.trace("TradeAction:TradeAction()"); 049 createTrade(); 050 } 051 052 public TradeAction(TradeServices trade) { 053 if (Log.doActionTrace()) 054 Log.trace("TradeAction:TradeAction(trade)"); 055 this.trade = trade; 056 } 057 058 private void createTrade() { 059 if (TradeConfig.runTimeMode == TradeConfig.EJB) { 060 try { 061 if (tradeHome == null) { 062 InitialContext ic = new InitialContext(); 063 try { 064 tradeHome = (TradeHome) (javax.rmi.PortableRemoteObject.narrow(ic.lookup("java:comp/env/ejb/Trade"), TradeHome.class)); 065 } 066 catch (Exception e) { 067 Log.log("TradeAction:createTrade lookup of java:comp/env/ejb/Trade failed. Reverting to JNDI lookup of Trade"); 068 tradeHome = (TradeHome) (javax.rmi.PortableRemoteObject.narrow(ic.lookup("Trade"), TradeHome.class)); 069 } 070 } 071 trade = tradeHome.create(); 072 } 073 catch (Exception e) { 074 Log.error("TradeAction:TradeAction() Creation of Trade EJB failed\n" + e); 075 e.printStackTrace(); 076 } 077 } else if (TradeConfig.runTimeMode == TradeConfig.JPA) { 078 try { 079 if (tradeHomeJPA == null) { 080 InitialContext ic = new InitialContext(); 081 try { 082 tradeHomeJPA = (TradeHome) (javax.rmi.PortableRemoteObject.narrow(ic.lookup("java:comp/env/ejb/TradeJPA"), TradeHome.class)); 083 } 084 catch (Exception e) { 085 Log.log("TradeAction:createTrade lookup of java:comp/env/ejb/TradeJPA failed. Reverting to JNDI lookup of Trade"); 086 tradeHomeJPA = (TradeHome) (javax.rmi.PortableRemoteObject.narrow(ic.lookup("TradeJPA"), TradeHome.class)); 087 } 088 } 089 trade = tradeHomeJPA.create(); 090 } 091 catch (Exception e) { 092 Log.error("TradeAction:TradeAction() Creation of Trade JPA failed\n" + e); 093 e.printStackTrace(); 094 } 095 } else if (TradeConfig.runTimeMode == TradeConfig.DIRECT) { 096 try { 097 trade = new TradeDirect(); 098 } 099 catch (Exception e) { 100 Log.error("TradeAction:TradeAction() Creation of Trade Direct failed\n" + e); 101 } 102 } else if (TradeConfig.runTimeMode == TradeConfig.SESSION) { 103 try { 104 if (tradeJDBCHome == null) { 105 InitialContext ic = new InitialContext(); 106 try { 107 tradeJDBCHome = (TradeJDBCHome) (javax.rmi.PortableRemoteObject.narrow(ic.lookup("java:comp/env/ejb/TradeJDBC"), TradeJDBCHome.class)); 108 } 109 catch (Exception e) { 110 Log.log("TradeAction:createTrade lookup of java:comp/env/ejb/TradeJDBC failed. Reverting to JNDI lookup of Trade"); 111 tradeJDBCHome = (TradeJDBCHome) (javax.rmi.PortableRemoteObject.narrow(ic.lookup("TradeJDBC"), TradeJDBCHome.class)); 112 } 113 } 114 trade = tradeJDBCHome.create(); 115 } 116 catch (Exception e) { 117 Log.error("TradeAction:TradeAction() Creation of Trade JDBC failed\n" + e); 118 e.printStackTrace(); 119 } 120 } 121 } 122 123 /** 124 * Compute and return a snapshot of the current market conditions This 125 * includes the TSIA - an index of the price of the top 100 Trade stock 126 * quotes The openTSIA ( the index at the open) The volume of shares traded, 127 * Top Stocks gain and loss 128 * 129 * @return A snapshot of the current market summary 130 */ 131 public MarketSummaryDataBean getMarketSummary() throws Exception { 132 if (Log.doActionTrace()) { 133 Log.trace("TradeAction:getMarketSummary()"); 134 } 135 MarketSummaryDataBean marketSummaryData = null; 136 marketSummaryData = trade.getMarketSummary(); 137 return marketSummaryData; 138 } 139 140 /** 141 * Purchase a stock and create a new holding for the given user. Given a 142 * stock symbol and quantity to purchase, retrieve the current quote price, 143 * debit the user's account balance, and add holdings to user's portfolio. 144 * 145 * @param userID the customer requesting the stock purchase 146 * @param symbol the symbol of the stock being purchased 147 * @param quantity the quantity of shares to purchase 148 * @return OrderDataBean providing the status of the newly created buy order 149 */ 150 public OrderDataBean buy(String userID, String symbol, double quantity, int orderProcessingMode) throws Exception { 151 if (Log.doActionTrace()) 152 Log.trace("TradeAction:buy", userID, symbol, new Double(quantity), new Integer(orderProcessingMode)); 153 OrderDataBean orderData; 154 orderData = trade.buy(userID, symbol, quantity, orderProcessingMode); 155 //after the purchase or sell of a stock, update the stocks volume and 156 // price 157 updateQuotePriceVolume(symbol, TradeConfig.getRandomPriceChangeFactor(), quantity); 158 return orderData; 159 } 160 161 /** 162 * Sell(SOAP 2.2 Wrapper converting int to Integer) a stock holding and 163 * removed the holding for the given user. Given a Holding, retrieve current 164 * quote, credit user's account, and reduce holdings in user's portfolio. 165 * 166 * @param userID the customer requesting the sell 167 * @param holdingID the users holding to be sold 168 * @return OrderDataBean providing the status of the newly created sell 169 * order 170 */ 171 public OrderDataBean sell(String userID, int holdingID, int orderProcessingMode) throws Exception { 172 return sell(userID, new Integer(holdingID), orderProcessingMode); 173 } 174 175 /** 176 * Sell a stock holding and removed the holding for the given user. Given a 177 * Holding, retrieve current quote, credit user's account, and reduce 178 * holdings in user's portfolio. 179 * 180 * @param userID the customer requesting the sell 181 * @param holdingID the users holding to be sold 182 * @return OrderDataBean providing the status of the newly created sell 183 * order 184 */ 185 public OrderDataBean sell(String userID, Integer holdingID, int orderProcessingMode) throws Exception { 186 if (Log.doActionTrace()) 187 Log.trace("TradeAction:sell", userID, holdingID, new Integer(orderProcessingMode)); 188 OrderDataBean orderData; 189 orderData = trade.sell(userID, holdingID, orderProcessingMode); 190 if (!(orderData.getOrderStatus().equalsIgnoreCase("cancelled"))) 191 //after the purchase or sell of a stock, update the stocks volume 192 // and price 193 updateQuotePriceVolume(orderData.getSymbol(), TradeConfig.getRandomPriceChangeFactor(), orderData.getQuantity()); 194 return orderData; 195 } 196 197 /** 198 * Queue the Order identified by orderID to be processed 199 * <p/> 200 * Orders are submitted through JMS to a Trading Broker and completed 201 * asynchronously. This method queues the order for processing 202 * <p/> 203 * The boolean twoPhase specifies to the server implementation whether or 204 * not the method is to participate in a global transaction 205 * 206 * @param orderID the Order being queued for processing 207 */ 208 public void queueOrder(Integer orderID, boolean twoPhase) { 209 throw new UnsupportedOperationException("TradeAction: queueOrder method not supported"); 210 } 211 212 /** 213 * Complete the Order identefied by orderID Orders are submitted through JMS 214 * to a Trading agent and completed asynchronously. This method completes 215 * the order For a buy, the stock is purchased creating a holding and the 216 * users account is debited For a sell, the stock holding is removed and the 217 * users account is credited with the proceeds 218 * <p/> 219 * The boolean twoPhase specifies to the server implementation whether or 220 * not the method is to participate in a global transaction 221 * 222 * @param orderID the Order to complete 223 * @return OrderDataBean providing the status of the completed order 224 */ 225 public OrderDataBean completeOrder(Integer orderID, boolean twoPhase) { 226 throw new UnsupportedOperationException("TradeAction: completeOrder method not supported"); 227 } 228 229 /** 230 * Cancel the Order identified by orderID 231 * <p/> 232 * Orders are submitted through JMS to a Trading Broker and completed 233 * asynchronously. This method queues the order for processing 234 * <p/> 235 * The boolean twoPhase specifies to the server implementation whether or 236 * not the method is to participate in a global transaction 237 * 238 * @param orderID the Order being queued for processing 239 */ 240 public void cancelOrder(Integer orderID, boolean twoPhase) { 241 throw new UnsupportedOperationException("TradeAction: cancelOrder method not supported"); 242 } 243 244 public void orderCompleted(String userID, Integer orderID) throws Exception { 245 if (Log.doActionTrace()) 246 Log.trace("TradeAction:orderCompleted", userID, orderID); 247 if (Log.doTrace()) 248 Log.trace("OrderCompleted", userID, orderID); 249 } 250 251 /** 252 * Get the collection of all orders for a given account 253 * 254 * @param userID the customer account to retrieve orders for 255 * @return Collection OrderDataBeans providing detailed order information 256 */ 257 public Collection getOrders(String userID) throws Exception { 258 if (Log.doActionTrace()) 259 Log.trace("TradeAction:getOrders", userID); 260 Collection orderDataBeans; 261 orderDataBeans = trade.getOrders(userID); 262 return orderDataBeans; 263 } 264 265 /** 266 * Get the collection of completed orders for a given account that need to 267 * be alerted to the user 268 * 269 * @param userID the customer account to retrieve orders for 270 * @return Collection OrderDataBeans providing detailed order information 271 */ 272 public Collection getClosedOrders(String userID) throws Exception { 273 if (Log.doActionTrace()) 274 Log.trace("TradeAction:getClosedOrders", userID); 275 Collection orderDataBeans; 276 orderDataBeans = trade.getClosedOrders(userID); 277 return orderDataBeans; 278 } 279 280 /** 281 * Given a market symbol, price, and details, create and return a new 282 * {@link QuoteDataBean} 283 * 284 * @param symbol the symbol of the stock 285 * @param price the current stock price 286 * @return a new QuoteDataBean or null if Quote could not be created 287 */ 288 public QuoteDataBean createQuote(String symbol, String companyName, BigDecimal price) throws Exception { 289 if (Log.doActionTrace()) 290 Log.trace("TradeAction:createQuote", symbol, companyName, price); 291 QuoteDataBean quoteData; 292 quoteData = trade.createQuote(symbol, companyName, price); 293 return quoteData; 294 } 295 296 /** 297 * Return a collection of {@link QuoteDataBean}describing all current 298 * quotes 299 * 300 * @return the collection of QuoteDataBean 301 */ 302 public Collection getAllQuotes() throws Exception { 303 if (Log.doActionTrace()) { 304 Log.trace("TradeAction:getAllQuotes"); 305 } 306 Collection quotes; 307 quotes = trade.getAllQuotes(); 308 return quotes; 309 } 310 311 /** 312 * Return a {@link QuoteDataBean}describing a current quote for the given 313 * stock symbol 314 * 315 * @param symbol the stock symbol to retrieve the current Quote 316 * @return the QuoteDataBean 317 */ 318 public QuoteDataBean getQuote(String symbol) throws Exception { 319 if (Log.doActionTrace()) 320 Log.trace("TradeAction:getQuote", symbol); 321 if ((symbol == null) || (symbol.length() == 0) || (symbol.length() > 10)) { 322 if (Log.doActionTrace()) { 323 Log.trace("TradeAction:getQuote --- primitive workload"); 324 } 325 return new QuoteDataBean("Invalid symbol", "", 0.0, FinancialUtils.ZERO, FinancialUtils.ZERO, FinancialUtils.ZERO, FinancialUtils.ZERO, 0.0); 326 } 327 QuoteDataBean quoteData; 328 quoteData = trade.getQuote(symbol); 329 return quoteData; 330 } 331 332 /** 333 * Update the stock quote price for the specified stock symbol 334 * 335 * @param symbol for stock quote to update 336 * @return the QuoteDataBean describing the stock 337 */ 338 /* avoid data collision with synch */ 339 public QuoteDataBean updateQuotePriceVolume(String symbol, BigDecimal changeFactor, double sharesTraded) throws Exception { 340 if (Log.doActionTrace()) 341 Log.trace("TradeAction:updateQuotePriceVolume", symbol, changeFactor, new Double(sharesTraded)); 342 QuoteDataBean quoteData = null; 343 try { 344 quoteData = trade.updateQuotePriceVolume(symbol, changeFactor, sharesTraded); 345 } 346 catch (Exception e) { 347 Log.error("TradeAction:updateQuotePrice -- ", e); 348 } 349 return quoteData; 350 } 351 352 /** 353 * Return the portfolio of stock holdings for the specified customer as a 354 * collection of HoldingDataBeans 355 * 356 * @param userID the customer requesting the portfolio 357 * @return Collection of the users portfolio of stock holdings 358 */ 359 public Collection getHoldings(String userID) throws Exception { 360 if (Log.doActionTrace()) 361 Log.trace("TradeAction:getHoldings", userID); 362 Collection holdingDataBeans; 363 holdingDataBeans = trade.getHoldings(userID); 364 return holdingDataBeans; 365 } 366 367 /** 368 * Return a specific user stock holding identifed by the holdingID 369 * 370 * @param holdingID the holdingID to return 371 * @return a HoldingDataBean describing the holding 372 */ 373 public HoldingDataBean getHolding(Integer holdingID) throws Exception { 374 if (Log.doActionTrace()) 375 Log.trace("TradeAction:getHolding", holdingID); 376 HoldingDataBean holdingData; 377 holdingData = trade.getHolding(holdingID); 378 return holdingData; 379 } 380 381 /** 382 * Return an AccountDataBean object for userID describing the account 383 * 384 * @param userID the account userID to lookup 385 * @return User account data in AccountDataBean 386 */ 387 public AccountDataBean getAccountData(String userID) throws javax.ejb.FinderException, RemoteException { 388 if (Log.doActionTrace()) 389 Log.trace("TradeAction:getAccountData", userID); 390 AccountDataBean accountData; 391 accountData = trade.getAccountData(userID); 392 return accountData; 393 } 394 395 /** 396 * Return an AccountProfileDataBean for userID providing the users profile 397 * 398 * @param userID the account userID to lookup 399 */ 400 public AccountProfileDataBean getAccountProfileData(String userID) throws Exception { 401 if (Log.doActionTrace()) 402 Log.trace("TradeAction:getAccountProfileData", userID); 403 AccountProfileDataBean accountProfileData; 404 accountProfileData = trade.getAccountProfileData(userID); 405 return accountProfileData; 406 } 407 408 /** 409 * Update userID's account profile information using the provided 410 * AccountProfileDataBean object 411 * 412 * @param accountProfileData account profile data in AccountProfileDataBean 413 */ 414 public AccountProfileDataBean updateAccountProfile(AccountProfileDataBean accountProfileData) throws Exception { 415 if (Log.doActionTrace()) 416 Log.trace("TradeAction:updateAccountProfile", accountProfileData); 417 accountProfileData = trade.updateAccountProfile(accountProfileData); 418 return accountProfileData; 419 } 420 421 /** 422 * Attempt to authenticate and login a user with the given password 423 * 424 * @param userID the customer to login 425 * @param password the password entered by the customer for authentication 426 * @return User account data in AccountDataBean 427 */ 428 public AccountDataBean login(String userID, String password) throws Exception { 429 if (Log.doActionTrace()) 430 Log.trace("TradeAction:login", userID, password); 431 AccountDataBean accountData; 432 accountData = trade.login(userID, password); 433 return accountData; 434 } 435 436 /** 437 * Logout the given user 438 * 439 * @param userID the customer to logout 440 */ 441 public void logout(String userID) throws Exception { 442 if (Log.doActionTrace()) 443 Log.trace("TradeAction:logout", userID); 444 trade.logout(userID); 445 } 446 447 /** 448 * Register a new Trade customer. Create a new user profile, user registry 449 * entry, account with initial balance, and empty portfolio. 450 * 451 * @param userID the new customer to register 452 * @param password the customers password 453 * @param fullname the customers fullname 454 * @param address the customers street address 455 * @param email the customers email address 456 * @param creditCard the customers creditcard number 457 * @param openBalance the amount to charge to the customers credit to open the 458 * account and set the initial balance 459 * @return the userID if successful, null otherwise 460 */ 461 public AccountDataBean register(String userID, String password, String fullname, String address, String email, String creditCard, BigDecimal openBalance) throws Exception { 462 if (Log.doActionTrace()) 463 Log.trace("TradeAction:register", userID, password, fullname, address, email, creditCard, openBalance); 464 AccountDataBean accountData; 465 accountData = trade.register(userID, password, fullname, address, email, creditCard, openBalance); 466 return accountData; 467 } 468 469 public AccountDataBean register(String userID, String password, String fullname, String address, String email, String creditCard, String openBalanceString) throws Exception { 470 BigDecimal openBalance = new BigDecimal(openBalanceString); 471 return register(userID, password, fullname, address, email, creditCard, openBalance); 472 } 473 474 /** 475 * Reset the TradeData by - removing all newly registered users by scenario 476 * servlet (i.e. users with userID's beginning with "ru:") * - removing all 477 * buy/sell order pairs - setting logoutCount = loginCount 478 * 479 * return statistics for this benchmark run 480 */ 481 public RunStatsDataBean resetTrade(boolean deleteAll) throws Exception { 482 RunStatsDataBean runStatsData; 483 runStatsData = trade.resetTrade(deleteAll); 484 return runStatsData; 485 } 486 }