| /** |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.openjpa.integration.daytrader; |
| |
| import java.math.BigDecimal; |
| import java.sql.Timestamp; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| |
| import javax.persistence.EntityManager; |
| import javax.persistence.EntityManagerFactory; |
| import javax.persistence.PersistenceUnit; |
| import javax.persistence.Query; |
| |
| import org.apache.openjpa.lib.log.Log; |
| |
| // import org.apache.geronimo.samples.daytrader.beans.AccountDataBean; |
| // import org.apache.geronimo.samples.daytrader.beans.AccountProfileDataBean; |
| // import org.apache.geronimo.samples.daytrader.beans.HoldingDataBean; |
| // import org.apache.geronimo.samples.daytrader.beans.OrderDataBean; |
| // import org.apache.geronimo.samples.daytrader.beans.QuoteDataBean; |
| // import org.apache.geronimo.samples.daytrader.core.FinancialUtils; |
| // import org.apache.geronimo.samples.daytrader.core.MarketSummaryDataBean; |
| // import org.apache.geronimo.samples.daytrader.core.RunStatsDataBean; |
| // import org.apache.geronimo.samples.daytrader.core.TradeDBServices; |
| // import org.apache.geronimo.samples.daytrader.core.TradeServices; |
| // import org.apache.geronimo.samples.daytrader.util.Log; |
| // import org.apache.geronimo.samples.daytrader.util.TradeConfig; |
| |
| /** |
| * TradeJPADirect uses JPA to implement the business methods of the Trade online |
| * broker application. These business methods represent the features and |
| * operations that can be performed by customers of the brokerage such as login, |
| * logout, get a stock quote, buy or sell a stock, etc. and are specified in the |
| * {@link org.apache.geronimo.samples.daytrader.TradeServices} interface |
| * |
| * Note: In order for this class to be thread-safe, a new TradeJPA must be |
| * created for each call to a method from the TradeInterface interface. |
| * Otherwise, pooled connections may not be released. |
| * |
| * @see org.apache.geronimo.samples.daytrader.TradeServices |
| * |
| */ |
| |
| // public class TradeJPADirect implements TradeServices, TradeDBServices { |
| public class TradeJPADirect { |
| |
| @PersistenceUnit(unitName="daytrader") |
| private static EntityManagerFactory emf; |
| |
| private static BigDecimal ZERO = new BigDecimal(0.0); |
| |
| private static boolean initialized = false; |
| |
| protected static Log log = null; |
| boolean _poolEm = true; |
| |
| EntityManager _em; |
| |
| public EntityManager getEm(EntityManagerFactory emf) { |
| if (_poolEm) { |
| if (_em == null) |
| _em = emf.createEntityManager(); |
| return _em; |
| } |
| return emf.createEntityManager(); |
| } |
| |
| public void putEm(EntityManager em){ |
| if(_poolEm) |
| em.clear(); |
| else{ |
| if(em.isOpen()) |
| em.close(); |
| } |
| } |
| |
| |
| // constructor for OpenJPA junit tests |
| public TradeJPADirect(Log log, EntityManagerFactory emf, boolean poolEm) { |
| TradeJPADirect.log = log; |
| TradeJPADirect.emf = emf; |
| _poolEm = poolEm; |
| if (!initialized) |
| init(); |
| } |
| |
| public static synchronized void init() { |
| if (initialized) |
| return; |
| |
| TradeConfig.setPublishQuotePriceChange(false); |
| initialized = true; |
| } |
| |
| public static void destroy() { |
| try { |
| if (!initialized) |
| return; |
| log.trace("TradeJPADirect:destroy"); |
| } |
| catch (Exception e) { |
| log.error("TradeJPADirect:destroy", e); |
| } |
| |
| } |
| |
| public MarketSummaryDataBean getMarketSummary() { |
| MarketSummaryDataBean marketSummaryData; |
| |
| /* |
| * Creating entiManager |
| */ |
| EntityManager entityManager = getEm(emf); |
| |
| try { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getMarketSummary -- getting market summary"); |
| |
| // Find Trade Stock Index Quotes (Top 100 quotes) |
| // ordered by their change in value |
| Collection<QuoteDataBean> quotes; |
| |
| Query query = entityManager.createNamedQuery("quoteejb.quotesByChange"); |
| quotes = query.getResultList(); |
| |
| QuoteDataBean[] quoteArray = (QuoteDataBean[]) quotes.toArray(new QuoteDataBean[quotes.size()]); |
| ArrayList<QuoteDataBean> topGainers = new ArrayList<>( |
| 5); |
| ArrayList<QuoteDataBean> topLosers = new ArrayList<>(5); |
| // BigDecimal TSIA = FinancialUtils.ZERO; |
| BigDecimal TSIA = (new BigDecimal(0.00)).setScale(2); |
| // BigDecimal openTSIA = FinancialUtils.ZERO; |
| BigDecimal openTSIA = (new BigDecimal(0.00)).setScale(2); |
| double totalVolume = 0.0; |
| |
| if (quoteArray.length > 5) { |
| for (int i = 0; i < 5; i++) |
| topGainers.add(quoteArray[i]); |
| for (int i = quoteArray.length - 1; i >= quoteArray.length - 5; i--) |
| topLosers.add(quoteArray[i]); |
| |
| for (QuoteDataBean quote : quoteArray) { |
| BigDecimal price = quote.getPrice(); |
| BigDecimal open = quote.getOpen(); |
| double volume = quote.getVolume(); |
| TSIA = TSIA.add(price); |
| openTSIA = openTSIA.add(open); |
| totalVolume += volume; |
| } |
| TSIA = TSIA.divide(new BigDecimal(quoteArray.length), |
| // FinancialUtils.ROUND); |
| BigDecimal.ROUND_HALF_UP); |
| openTSIA = openTSIA.divide(new BigDecimal(quoteArray.length), |
| // FinancialUtils.ROUND); |
| BigDecimal.ROUND_HALF_UP); |
| } |
| |
| marketSummaryData = new MarketSummaryDataBean(TSIA, openTSIA, |
| totalVolume, topGainers, topLosers); |
| } |
| catch (Exception e) { |
| log.error("TradeJPADirect:getMarketSummary", e); |
| throw new RuntimeException("TradeJPADirect:getMarketSummary -- error ", e); |
| } finally { |
| putEm(entityManager); |
| } |
| |
| return marketSummaryData; |
| } |
| |
| public OrderDataBean buy(String userID, String symbol, double quantity, int orderProcessingMode) { |
| OrderDataBean order = null; |
| BigDecimal total; |
| /* |
| * creating entitymanager |
| */ |
| EntityManager entityManager = getEm(emf); |
| |
| try { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:buy - userID=" + userID + " symbol=" + symbol + " quantity=" + quantity); |
| |
| entityManager.getTransaction().begin(); |
| |
| AccountProfileDataBean profile = entityManager.find(AccountProfileDataBean.class, userID); |
| AccountDataBean account = profile.getAccount(); |
| QuoteDataBean quote = entityManager.find(QuoteDataBean.class, symbol); |
| HoldingDataBean holding = null; // The holding will be created by this buy order |
| order = createOrder(account, quote, holding, "buy", quantity, entityManager); |
| // order = createOrder(account, quote, holding, "buy", quantity); |
| // UPDATE - account should be credited during completeOrder |
| BigDecimal price = quote.getPrice(); |
| BigDecimal orderFee = order.getOrderFee(); |
| BigDecimal balance = account.getBalance(); |
| total = (new BigDecimal(quantity).multiply(price)).add(orderFee); |
| account.setBalance(balance.subtract(total)); |
| |
| // commit the transaction before calling completeOrder |
| entityManager.getTransaction().commit(); |
| |
| if (orderProcessingMode == TradeConfig.SYNCH) |
| completeOrder(order.getOrderID(), false); |
| else if (orderProcessingMode == TradeConfig.ASYNCH_2PHASE) |
| queueOrder(order.getOrderID(), true); |
| } catch (Exception e) { |
| log.error("TradeJPADirect:buy(" + userID + "," + symbol + "," + quantity + ") --> failed", e); |
| /* On exception - cancel the order */ |
| // TODO figure out how to do this with JPA |
| if (order != null) |
| order.cancel(); |
| if (entityManager.getTransaction().isActive()) |
| entityManager.getTransaction().rollback(); |
| // throw new EJBException(e); |
| throw new RuntimeException(e); |
| } finally { |
| if (entityManager != null) { |
| putEm(entityManager); |
| entityManager = null; |
| } |
| } |
| // after the purchase or sell of a stock, update the stocks volume and |
| // price |
| updateQuotePriceVolume(symbol, TradeConfig.getRandomPriceChangeFactor(), quantity); |
| return order; |
| } |
| |
| public OrderDataBean sell(String userID, Integer holdingID, |
| int orderProcessingMode) { |
| EntityManager entityManager = getEm(emf); |
| |
| OrderDataBean order = null; |
| BigDecimal total; |
| try { |
| entityManager.getTransaction().begin(); |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:sell - userID=" + userID + " holding=" + holdingID); |
| |
| AccountProfileDataBean profile = entityManager.find(AccountProfileDataBean.class, userID); |
| |
| AccountDataBean account = profile.getAccount(); |
| HoldingDataBean holding = entityManager.find(HoldingDataBean.class, holdingID); |
| |
| if (holding == null) { |
| log.error("TradeJPADirect:sell User " + userID |
| + " attempted to sell holding " + holdingID |
| + " which has already been sold"); |
| |
| OrderDataBean orderData = new OrderDataBean(); |
| orderData.setOrderStatus("cancelled"); |
| |
| entityManager.persist(orderData); |
| entityManager.getTransaction().commit(); |
| return orderData; |
| } |
| |
| QuoteDataBean quote = holding.getQuote(); |
| double quantity = holding.getQuantity(); |
| |
| order = createOrder(account, quote, holding, "sell", quantity, |
| entityManager); |
| // UPDATE the holding purchase data to signify this holding is |
| // "inflight" to be sold |
| // -- could add a new holdingStatus attribute to holdingEJB |
| holding.setPurchaseDate(new java.sql.Timestamp(0)); |
| |
| // UPDATE - account should be credited during completeOrder |
| BigDecimal price = quote.getPrice(); |
| BigDecimal orderFee = order.getOrderFee(); |
| BigDecimal balance = account.getBalance(); |
| total = (new BigDecimal(quantity).multiply(price)).subtract(orderFee); |
| |
| account.setBalance(balance.add(total)); |
| |
| // commit the transaction before calling completeOrder |
| entityManager.getTransaction().commit(); |
| |
| if (orderProcessingMode == TradeConfig.SYNCH) |
| completeOrder(order.getOrderID(), false); |
| else if (orderProcessingMode == TradeConfig.ASYNCH_2PHASE) |
| queueOrder(order.getOrderID(), true); |
| |
| } |
| catch (Exception e) { |
| log.error("TradeJPADirect:sell(" + userID + "," + holdingID + ") --> failed", e); |
| // TODO figure out JPA cancel |
| if (order != null) |
| order.cancel(); |
| entityManager.getTransaction().rollback(); |
| throw new RuntimeException("TradeJPADirect:sell(" + userID + "," + holdingID + ")", e); |
| } finally { |
| if (entityManager != null) { |
| putEm(entityManager); |
| } |
| } |
| |
| if (!(order.getOrderStatus().equalsIgnoreCase("cancelled"))) |
| //after the purchase or sell of a stock, update the stocks volume and price |
| updateQuotePriceVolume(order.getSymbol(), TradeConfig.getRandomPriceChangeFactor(), order.getQuantity()); |
| |
| return order; |
| } |
| |
| public void queueOrder(Integer orderID, boolean twoPhase) { |
| log.error("TradeJPADirect:queueOrder() not implemented for this runtime mode"); |
| throw new UnsupportedOperationException("TradeJPADirect:queueOrder() not implemented for this runtime mode"); |
| } |
| |
| public OrderDataBean completeOrder(Integer orderID, boolean twoPhase) |
| throws Exception { |
| EntityManager entityManager = getEm(emf); |
| OrderDataBean order = null; |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:completeOrder - orderId=" + orderID + " twoPhase=" + twoPhase); |
| |
| try { |
| order = entityManager.find(OrderDataBean.class, orderID); |
| order.getQuote(); |
| |
| if (order == null) { |
| log.error("TradeJPADirect:completeOrder -- Unable to find orderID=" + orderID); |
| return null; |
| } |
| |
| if (order.isCompleted()) { |
| throw new RuntimeException("Error: attempt to complete Order that is already completed\n" + order); |
| } |
| |
| AccountDataBean account = order.getAccount(); |
| QuoteDataBean quote = order.getQuote(); |
| HoldingDataBean holding = order.getHolding(); |
| BigDecimal price = order.getPrice(); |
| double quantity = order.getQuantity(); |
| |
| String userID = account.getProfile().getUserID(); |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:completeOrder--> Completing Order " |
| + order.getOrderID() + "\n\t Order info: " + order |
| + "\n\t Account info: " + account + "\n\t Quote info: " |
| + quote + "\n\t Holding info: " + holding); |
| |
| HoldingDataBean newHolding = null; |
| if (order.isBuy()) { |
| /* |
| * Complete a Buy operation - create a new Holding for the Account - |
| * deduct the Order cost from the Account balance |
| */ |
| newHolding = createHolding(account, quote, quantity, price, entityManager); |
| } |
| |
| entityManager.getTransaction().begin(); |
| |
| if (newHolding != null) { |
| order.setHolding(newHolding); |
| } |
| |
| if (order.isSell()) { |
| /* |
| * Complete a Sell operation - remove the Holding from the Account - |
| * deposit the Order proceeds to the Account balance |
| */ |
| if (holding == null) { |
| log.error("TradeJPADirect:completeOrder -- Unable to sell order " + order.getOrderID() |
| + ", holding already sold (null)"); |
| order.cancel(); |
| entityManager.getTransaction().commit(); |
| return order; |
| } |
| else { |
| entityManager.remove(holding); |
| order.setHolding(null); |
| } |
| } |
| |
| order.setOrderStatus("closed"); |
| order.setCompletionDate(new java.sql.Timestamp(System.currentTimeMillis())); |
| entityManager.persist(order); |
| entityManager.getTransaction().commit(); |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:completeOrder--> Completed Order " |
| + order.getOrderID() + "\n\t Order info: " + order |
| + "\n\t Account info: " + account + "\n\t Quote info: " |
| + quote + "\n\t Holding info: " + newHolding); |
| |
| } catch (Exception e) { |
| log.error("TradeJPADirect:completeOrder() failed for orderID=" + orderID, e); |
| if (entityManager.getTransaction().isActive()) |
| entityManager.getTransaction().rollback(); |
| } finally { |
| if (entityManager != null) { |
| putEm(entityManager); |
| } |
| } |
| |
| return order; |
| } |
| |
| public void cancelOrder(Integer orderID, boolean twoPhase) { |
| EntityManager entityManager = getEm(emf); |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:cancelOrder - orderId=" + orderID + " twoPhase=" + twoPhase); |
| |
| OrderDataBean order = entityManager.find(OrderDataBean.class, orderID); |
| /* |
| * managed transaction |
| */ |
| try { |
| entityManager.getTransaction().begin(); |
| order.cancel(); |
| entityManager.getTransaction().commit(); |
| } |
| catch (Exception e) { |
| entityManager.getTransaction().rollback(); |
| } finally { |
| putEm(entityManager); |
| } |
| } |
| |
| public void orderCompleted(String userID, Integer orderID) { |
| if (log.isTraceEnabled()) |
| log.trace("TradeAction:orderCompleted - userID=" + userID + " orderID=" + orderID); |
| } |
| |
| public Collection<OrderDataBean> getOrders(String userID) { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getOrders - userID=" + userID); |
| EntityManager entityManager = getEm(emf); |
| AccountProfileDataBean profile = entityManager.find( |
| AccountProfileDataBean.class, userID); |
| AccountDataBean account = profile.getAccount(); |
| putEm(entityManager); |
| return account.getOrders(); |
| } |
| |
| public Collection<OrderDataBean> getClosedOrders(String userID) { |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getClosedOrders - userID=" + userID); |
| EntityManager entityManager = getEm(emf); |
| |
| try { |
| |
| // Get the primary keys for all the closed Orders for this |
| // account. |
| /* |
| * managed transaction |
| */ |
| entityManager.getTransaction().begin(); |
| Query query = entityManager |
| .createNamedQuery("orderejb.closedOrders"); |
| query.setParameter("userID", userID); |
| |
| entityManager.getTransaction().commit(); |
| Collection results = query.getResultList(); |
| Iterator itr = results.iterator(); |
| // entityManager.joinTransaction(); |
| // Spin through the orders to populate the lazy quote fields |
| while (itr.hasNext()) { |
| OrderDataBean thisOrder = (OrderDataBean) itr.next(); |
| thisOrder.getQuote(); |
| } |
| |
| if (TradeConfig.jpaLayer == TradeConfig.OPENJPA) { |
| Query updateStatus = entityManager |
| .createNamedQuery("orderejb.completeClosedOrders"); |
| /* |
| * managed transaction |
| */ |
| try { |
| entityManager.getTransaction().begin(); |
| updateStatus.setParameter("userID", userID); |
| |
| updateStatus.executeUpdate(); |
| entityManager.getTransaction().commit(); |
| } |
| catch (Exception e) { |
| entityManager.getTransaction().rollback(); |
| putEm(entityManager); |
| } |
| } |
| else if (TradeConfig.jpaLayer == TradeConfig.HIBERNATE) { |
| /* |
| * Add logic to do update orders operation, because JBoss5' |
| * Hibernate 3.3.1GA DB2Dialect and MySQL5Dialect do not work |
| * with annotated query "orderejb.completeClosedOrders" defined |
| * in OrderDatabean |
| */ |
| Query findaccountid = entityManager.createNativeQuery( |
| "select " |
| + "a.ACCOUNTID, " |
| + "a.LOGINCOUNT, " |
| + "a.LOGOUTCOUNT, " |
| + "a.LASTLOGIN, " |
| + "a.CREATIONDATE, " |
| + "a.BALANCE, " |
| + "a.OPENBALANCE, " |
| + "a.PROFILE_USERID " |
| + "from accountejb a where a.profile_userid = ?", |
| org.apache.openjpa.integration.daytrader.AccountDataBean.class); |
| findaccountid.setParameter(1, userID); |
| AccountDataBean account = (AccountDataBean) findaccountid.getSingleResult(); |
| Integer accountid = account.getAccountID(); |
| Query updateStatus = entityManager.createNativeQuery( |
| "UPDATE orderejb o SET o.orderStatus = 'completed' WHERE " |
| + "o.orderStatus = 'closed' AND o.ACCOUNT_ACCOUNTID = ?"); |
| updateStatus.setParameter(1, accountid); |
| updateStatus.executeUpdate(); |
| } |
| if (entityManager != null) { |
| putEm(entityManager); |
| } |
| return results; |
| } catch (Exception e) { |
| log.error("TradeJPADirect.getClosedOrders", e); |
| putEm(entityManager); |
| throw new RuntimeException("TradeJPADirect.getClosedOrders - error", e); |
| |
| } finally { |
| if (entityManager != null) { |
| putEm(entityManager); |
| } |
| } |
| } |
| |
| public QuoteDataBean createQuote(String symbol, String companyName, |
| BigDecimal price) { |
| EntityManager entityManager = getEm(emf); |
| QuoteDataBean quote = null; |
| try { |
| quote = new QuoteDataBean(symbol, companyName, 0, price, price, price, price, 0); |
| /* |
| * managed transaction |
| */ |
| entityManager.getTransaction().begin(); |
| entityManager.persist(quote); |
| entityManager.getTransaction().commit(); |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:createQuote-->" + quote); |
| return quote; |
| } catch (Exception e) { |
| log.error("TradeJPADirect:createQuote -- exception creating Quote=" + quote, e); |
| if (entityManager.getTransaction().isActive()) |
| entityManager.getTransaction().rollback(); |
| throw new RuntimeException(e); |
| } finally { |
| if (entityManager != null) { |
| putEm(entityManager); |
| } |
| } |
| |
| } |
| |
| public QuoteDataBean getQuote(String symbol) { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getQuote - symbol=" + symbol); |
| EntityManager entityManager = getEm(emf); |
| |
| QuoteDataBean qdb = entityManager.find(QuoteDataBean.class, symbol); |
| |
| if (entityManager != null) { |
| putEm(entityManager); |
| } |
| return qdb; |
| } |
| |
| public Collection<QuoteDataBean> getAllQuotes() { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getAllQuotes"); |
| EntityManager entityManager = getEm(emf); |
| |
| Query query = entityManager.createNamedQuery("quoteejb.allQuotes"); |
| |
| if (entityManager != null) { |
| putEm(entityManager); |
| |
| } |
| return query.getResultList(); |
| } |
| |
| public QuoteDataBean updateQuotePriceVolume(String symbol, |
| BigDecimal changeFactor, double sharesTraded) { |
| if (!TradeConfig.getUpdateQuotePrices()) |
| return new QuoteDataBean(); |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:updateQuote - symbol=" + symbol + "changeFactor=" + changeFactor); |
| |
| /* |
| * Add logic to determine JPA layer, because JBoss5' Hibernate 3.3.1GA |
| * DB2Dialect and MySQL5Dialect do not work with annotated query |
| * "quoteejb.quoteForUpdate" defined in QuoteDatabean |
| */ |
| EntityManager entityManager = getEm(emf); |
| QuoteDataBean quote = null; |
| if (TradeConfig.jpaLayer == TradeConfig.HIBERNATE) { |
| quote = entityManager.find(QuoteDataBean.class, symbol); |
| } else if (TradeConfig.jpaLayer == TradeConfig.OPENJPA) { |
| |
| Query q = entityManager.createNamedQuery("quoteejb.quoteForUpdate"); |
| q.setParameter(1, symbol); |
| |
| quote = (QuoteDataBean) q.getSingleResult(); |
| } |
| |
| BigDecimal oldPrice = quote.getPrice(); |
| |
| if (quote.getPrice().equals(TradeConfig.PENNY_STOCK_PRICE)) { |
| changeFactor = TradeConfig.PENNY_STOCK_RECOVERY_MIRACLE_MULTIPLIER; |
| } |
| |
| BigDecimal newPrice = changeFactor.multiply(oldPrice).setScale(2, BigDecimal.ROUND_HALF_UP); |
| |
| /* |
| * managed transaction |
| */ |
| |
| try { |
| |
| quote.setPrice(newPrice); |
| quote.setVolume(quote.getVolume() + sharesTraded); |
| quote.setChange((newPrice.subtract(quote.getOpen()).doubleValue())); |
| |
| entityManager.getTransaction().begin(); |
| entityManager.merge(quote); |
| entityManager.getTransaction().commit(); |
| } |
| catch (Exception e) { |
| entityManager.getTransaction().rollback(); |
| } finally { |
| if (entityManager != null) { |
| putEm(entityManager); |
| } |
| } |
| |
| this.publishQuotePriceChange(quote, oldPrice, changeFactor, sharesTraded); |
| |
| return quote; |
| } |
| |
| public Collection<HoldingDataBean> getHoldings(String userID) { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getHoldings - userID=" + userID); |
| EntityManager entityManager = getEm(emf); |
| /* |
| * managed transaction |
| */ |
| entityManager.getTransaction().begin(); |
| |
| Query query = entityManager.createNamedQuery("holdingejb.holdingsByUserID"); |
| query.setParameter("userID", userID); |
| |
| entityManager.getTransaction().commit(); |
| Collection<HoldingDataBean> holdings = query.getResultList(); |
| /* |
| * Inflate the lazy data memebers |
| */ |
| Iterator itr = holdings.iterator(); |
| while (itr.hasNext()) { |
| ((HoldingDataBean) itr.next()).getQuote(); |
| } |
| |
| putEm(entityManager); |
| return holdings; |
| } |
| |
| public HoldingDataBean getHolding(Integer holdingID) { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getHolding - holdingID=" + holdingID); |
| HoldingDataBean holding; |
| EntityManager entityManager = getEm(emf); |
| holding = entityManager.find(HoldingDataBean.class, holdingID); |
| putEm(entityManager); |
| return holding; |
| } |
| |
| public AccountDataBean getAccountData(String userID) { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getAccountData - userID=" + userID); |
| |
| EntityManager entityManager = getEm(emf); |
| |
| AccountProfileDataBean profile = entityManager.find(AccountProfileDataBean.class, userID); |
| /* |
| * Inflate the lazy data memebers |
| */ |
| AccountDataBean account = profile.getAccount(); |
| account.getProfile(); |
| |
| // Added to populate transient field for account |
| account.setProfileID(profile.getUserID()); |
| putEm(entityManager); |
| |
| return account; |
| } |
| |
| public AccountProfileDataBean getAccountProfileData(String userID) { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:getProfileData - userID=" + userID); |
| EntityManager entityManager = getEm(emf); |
| |
| AccountProfileDataBean apb = entityManager.find(AccountProfileDataBean.class, userID); |
| putEm(entityManager); |
| return apb; |
| } |
| |
| public AccountProfileDataBean updateAccountProfile(AccountProfileDataBean profileData) { |
| |
| EntityManager entityManager = getEm(emf); |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:updateAccountProfileData - profileData=" + profileData); |
| /* |
| * // Retrieve the previous account profile in order to get account |
| * data... hook it into new object AccountProfileDataBean temp = |
| * entityManager.find(AccountProfileDataBean.class, |
| * profileData.getUserID()); // In order for the object to merge |
| * correctly, the account has to be hooked into the temp object... // - |
| * may need to reverse this and obtain the full object first |
| * |
| * profileData.setAccount(temp.getAccount()); |
| * |
| * //TODO this might not be correct temp = |
| * entityManager.merge(profileData); //System.out.println(temp); |
| */ |
| |
| AccountProfileDataBean temp = entityManager.find(AccountProfileDataBean.class, profileData.getUserID()); |
| temp.setAddress(profileData.getAddress()); |
| temp.setPassword(profileData.getPassword()); |
| temp.setFullName(profileData.getFullName()); |
| temp.setCreditCard(profileData.getCreditCard()); |
| temp.setEmail(profileData.getEmail()); |
| /* |
| * Managed Transaction |
| */ |
| try { |
| |
| entityManager.getTransaction().begin(); |
| entityManager.merge(temp); |
| entityManager.getTransaction().commit(); |
| } |
| catch (Exception e) { |
| entityManager.getTransaction().rollback(); |
| } finally { |
| putEm(entityManager); |
| } |
| |
| return temp; |
| } |
| |
| public AccountDataBean login(String userID, String password) |
| throws Exception { |
| |
| EntityManager entityManager = getEm(emf); |
| |
| AccountProfileDataBean profile = entityManager.find(AccountProfileDataBean.class, userID); |
| |
| if (profile == null) { |
| throw new RuntimeException("No such user: " + userID); |
| } |
| /* |
| * Managed Transaction |
| */ |
| entityManager.getTransaction().begin(); |
| entityManager.merge(profile); |
| |
| AccountDataBean account = profile.getAccount(); |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:login - userID=" + userID + " password=" + password); |
| |
| account.login(password); |
| entityManager.getTransaction().commit(); |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:login(" + userID + "," + password + ") success" + account); |
| putEm(entityManager); |
| return account; |
| } |
| |
| public void logout(String userID) { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:logout - userID=" + userID); |
| EntityManager entityManager = getEm(emf); |
| |
| AccountProfileDataBean profile = entityManager.find(AccountProfileDataBean.class, userID); |
| AccountDataBean account = profile.getAccount(); |
| |
| /* |
| * Managed Transaction |
| */ |
| try { |
| entityManager.getTransaction().begin(); |
| account.logout(); |
| entityManager.getTransaction().commit(); |
| } |
| catch (Exception e) { |
| entityManager.getTransaction().rollback(); |
| } finally { |
| putEm(entityManager); |
| } |
| |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:logout(" + userID + ") success"); |
| } |
| |
| public AccountDataBean register(String userID, String password, String fullname, |
| String address, String email, String creditcard, |
| BigDecimal openBalance) { |
| AccountDataBean account = null; |
| AccountProfileDataBean profile = null; |
| EntityManager entityManager = getEm(emf); |
| |
| if (log.isTraceEnabled()) { |
| //Log.trace("TradeJPADirect:register", userID, password, fullname, address, email, creditcard, openBalance); |
| log.trace("TradeJPADirect:register - userID=" + userID); |
| } |
| |
| // Check to see if a profile with the desired userID already exists |
| profile = entityManager.find(AccountProfileDataBean.class, userID); |
| if (profile != null) { |
| log.error("Failed to register new Account - AccountProfile with userID(" + userID + ") already exists"); |
| return null; |
| } |
| else { |
| profile = new AccountProfileDataBean(userID, password, fullname, |
| address, email, creditcard); |
| account = new AccountDataBean(0, 0, null, new Timestamp(System.currentTimeMillis()), |
| openBalance, openBalance, userID); |
| profile.setAccount(account); |
| account.setProfile(profile); |
| /* |
| * managed Transaction |
| */ |
| try { |
| entityManager.getTransaction().begin(); |
| entityManager.persist(profile); |
| entityManager.persist(account); |
| entityManager.getTransaction().commit(); |
| } |
| catch (Exception e) { |
| log.error("Failed to create account and profile for userId=" + userID, e); |
| entityManager.getTransaction().rollback(); |
| } finally { |
| putEm(entityManager); |
| } |
| |
| } |
| |
| return account; |
| } |
| |
| // @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) |
| //public RunStatsDataBean resetTrade(boolean deleteAll) throws Exception { |
| public void resetTrade(boolean deleteAll) throws Exception { |
| // return(new TradeJDBCDirect(false)).resetTrade(deleteAll); |
| new RuntimeException("TradeJPADirect:resetTrade - not implemented in JPA mode"); |
| } |
| |
| /* |
| * NO LONGER USE |
| */ |
| |
| private void publishQuotePriceChange(QuoteDataBean quote, |
| BigDecimal oldPrice, BigDecimal changeFactor, double sharesTraded) { |
| if (!TradeConfig.getPublishQuotePriceChange()) |
| return; |
| log.error("TradeJPADirect:publishQuotePriceChange - is not implemented for this runtime mode"); |
| throw new UnsupportedOperationException( |
| "TradeJPADirect:publishQuotePriceChange - is not implemented for this runtime mode"); |
| } |
| |
| /* |
| * new Method() that takes EntityManager as a parameter |
| */ |
| private OrderDataBean createOrder(AccountDataBean account, |
| QuoteDataBean quote, HoldingDataBean holding, String orderType, |
| double quantity, EntityManager entityManager) { |
| OrderDataBean order; |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:createOrder(orderID=" + " account=" |
| + ((account == null) ? null : account.getAccountID()) |
| + " quote=" + ((quote == null) ? null : quote.getSymbol()) |
| + " orderType=" + orderType + " quantity=" + quantity); |
| try { |
| order = new OrderDataBean(orderType, |
| "open", |
| new Timestamp(System.currentTimeMillis()), |
| null, |
| quantity, |
| // quote.getPrice().setScale(FinancialUtils.SCALE, FinancialUtils.ROUND), |
| quote.getPrice().setScale(2, BigDecimal.ROUND_HALF_UP), |
| TradeConfig.getOrderFee(orderType), |
| account, |
| quote, |
| holding); |
| entityManager.persist(order); |
| } |
| catch (Exception e) { |
| log.error("TradeJPADirect:createOrder -- failed to create Order", e); |
| throw new RuntimeException("TradeJPADirect:createOrder -- failed to create Order", e); |
| } |
| return order; |
| } |
| |
| private HoldingDataBean createHolding(AccountDataBean account, |
| QuoteDataBean quote, double quantity, BigDecimal purchasePrice, |
| EntityManager entityManager) throws Exception { |
| HoldingDataBean newHolding = new HoldingDataBean(quantity, |
| purchasePrice, new Timestamp(System.currentTimeMillis()), |
| account, quote); |
| try { |
| /* |
| * manage transactions |
| */ |
| entityManager.getTransaction().begin(); |
| entityManager.persist(newHolding); |
| entityManager.getTransaction().commit(); |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:createHolding(account=" + ((account == null) ? null : account.getAccountID()) |
| + " quote=" + ((quote == null) ? null : quote.getSymbol()) |
| + " quantity=" + quantity + " purchasePrice=" + purchasePrice + ")"); |
| } |
| catch (Exception e) { |
| log.error("createHolding() failed for newHolding=" + newHolding, e); |
| entityManager.getTransaction().rollback(); |
| } |
| return newHolding; |
| } |
| |
| public double investmentReturn(double investment, double NetValue) |
| throws Exception { |
| if (log.isTraceEnabled()) |
| log.trace("TradeJPADirect:investmentReturn"); |
| |
| double diff = NetValue - investment; |
| double ir = diff / investment; |
| return ir; |
| } |
| |
| public QuoteDataBean pingTwoPhase(String symbol) throws Exception { |
| log.error("TradeJPADirect:pingTwoPhase - is not implemented for this runtime mode"); |
| throw new UnsupportedOperationException( |
| "TradeJPADirect:pingTwoPhase - is not implemented for this runtime mode"); |
| } |
| |
| class quotePriceComparator implements java.util.Comparator { |
| @Override |
| public int compare(Object quote1, Object quote2) { |
| double change1 = ((QuoteDataBean) quote1).getChange(); |
| double change2 = ((QuoteDataBean) quote2).getChange(); |
| return new Double(change2).compareTo(change1); |
| } |
| } |
| |
| /** |
| * TradeBuildDB needs this abstracted method |
| */ |
| public String checkDBProductName() throws Exception { |
| log.error("TradeJPADirect:checkDBProductName - is not implemented in JPA mode"); |
| // return(new TradeJDBCDirect(false)).checkDBProductName(); |
| new RuntimeException("TradeJPADirect:checkDBProductName - is not implemented in JPA mode"); |
| return null; |
| } |
| |
| /** |
| * TradeBuildDB needs this abstracted method |
| */ |
| public boolean recreateDBTables(Object[] sqlBuffer, java.io.PrintWriter out) |
| throws Exception { |
| log.error("TradeJPADirect:recreateDBTables - is not implemented in JPA mode"); |
| //return(new TradeJDBCDirect(false)).recreateDBTables(sqlBuffer, out); |
| new RuntimeException("TradeJPADirect:recreateDBTables - is not implemented in JPA mode"); |
| return false; |
| } |
| |
| /** |
| * Get mode - returns the persistence mode (TradeConfig.JPA) |
| * |
| * @return int mode |
| */ |
| public int getMode() { |
| return TradeConfig.JPA; |
| } |
| |
| } |