package examples.xml.biztalk.ejb.biztrader;

import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.*;
import javax.ejb.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import examples.xml.biztalk.*;
import org.w3c.dom.Element;

/**
 * BizTraderBean is a stateless SessionBean. It is based off of 
 * <tt>examples.ejb.basic.statelessSession.TraderBean</tt>. This bean also 
 * implements the <tt>examples.xml.biztalk.ejb.BizBean</tt> interface and 
 * illustrates:
 * <ul>
 * <li> No persistence of state between calls to the SessionBean
 * <li> Application-defined exceptions
 * </ul>
 *
 * @author Copyright (c) 2000 by BEA Systems, Inc. All Rights Reserved.
 */
public class BizTraderBean implements SessionBean {
  static  final     boolean        VERBOSE = true;

  // -----------------------------------------------------------------
  // private variables
  private SessionContext ctx;
  private Context        rootCtx;


  // -----------------------------------------------------------------
  // SessionBean implementation

  /**
   * This method is required by the EJB Specification,
   * but is not used by this example.
   *
   */
  public void ejbActivate() {
    if (VERBOSE)
      System.out.println("ejbActivate called");
  }

  /**
   * This method is required by the EJB Specification,
   * but is not used by this example.
   *
   */
  public void ejbRemove() {
    if (VERBOSE)
      System.out.println("ejbRemove called");
  }

  /**
   * This method is required by the EJB Specification,
   * but is not used by this example.
   *
   */
  public void ejbPassivate() {
    if (VERBOSE)
      System.out.println("ejbPassivate called");
  }

  /**
   * Sets the session context.
   *
   * @param ctx               SessionContext Context for session
   */
  public void setSessionContext(SessionContext ctx) {
    if (VERBOSE)
      System.out.println("setSessionContext called");
    this.ctx = ctx;
  }

  // Interface exposed to EJBObject (pretty much a clone of the 
  // Trader interface without the RemoteException stuff, and an ejbCreate
  // without any parameters

  /**
   * This method corresponds to the create method in the home interface
   * "BizBeanHome.java".
   * The parameter sets of the two methods are identical. When the client calls
   * <code>BizBeanHome.create()</code>, the container allocates an instance of 
   * the EJBean and calls <code>ejbCreate()</code>.
   *
   * @exception               javax.ejb.CreateException if there is
   *                          a communications or systems failure
   * @see                     examples.xml.biztalk.ejb.biztrader.BizTraderBean
   */
  public void ejbCreate () throws CreateException {
    if (VERBOSE)
      System.out.println("ejbCreate called");
    try {
      Properties p = new Properties();
      p.put(Context.INITIAL_CONTEXT_FACTORY,
        "weblogic.jndi.WLInitialContextFactory");
      InitialContext ic = new InitialContext(p);
      rootCtx = (Context) ic.lookup("java:comp/env");
    } catch (NamingException ne) {
      throw new CreateException("Could not look up context");
    }
  }

  /**
   * Buys shares of a stock for a named customer.
   *
   * @param customerName      String Customer name
   * @param stockSymbol       String Stock symbol
   * @param shares            int Number of shares to buy
   * @exception               examples.xml.biztalk.ejb.biztrader.ProcessingErrorException
   *                          if there is an error while buying the shares
   */
  public void buy(String customerName, String stockSymbol, 
                         int shares)
    throws ProcessingErrorException
  {
    if (VERBOSE && shares >= 0) {
      System.out.println("buy (" + customerName + ", " + 
                         stockSymbol + ", " +
                         shares + ")");
    }
    String str = null;
    int tradeLimit = getTradeLimit();
    try {
      if (shares > tradeLimit)
        shares = tradeLimit;
      else if (shares < -tradeLimit) // limit for selling
        shares = -tradeLimit;
      
      double price = getStockPrice(stockSymbol);

      if (VERBOSE) {
        str = "insert into trading orders " + 
              "(account, stockSymbol, shares, price) VALUES (" +
              "'" + customerName + "'" + "," +
              "'" + stockSymbol  + "'" + "," +
              shares + "," + 
              price  + ")";
        System.out.println ("Executing stmt: " + str);
      }
      if (shares < 0) 
        shares = -shares;
    }
    catch (Exception e) {
      throw new ProcessingErrorException("Trader error: " + e);
    }
  }

  /**
   * Sells shares of a stock for a named customer.
   *
   * @param customerName      String Customer name
   * @param stockSymbol       String Stock symbol
   * @param shares            int Number of shares to buy
   * @exception               examples.xml.biztalk.ejb.biztrader.ProcessingErrorException
   *                          if there is an error while selling the shares
   */
  public void sell(String customerName, String stockSymbol, int shares)
    throws ProcessingErrorException
  {
    if (VERBOSE) {
      System.out.println("sell (" + customerName + ", " + 
                         stockSymbol + ", " +
                         shares + ")");
    }

    // convert "sell 100 shares" to "buy -100 shares"
    buy (customerName, stockSymbol, -shares);
  }


  // The following routines illustrate getting information
  // from the environment.

  /**
   * Returns the trading limit.
   *
   * @return                  int Trading limit
   */
  private int getTradeLimit()
    throws ProcessingErrorException
  {
    try {
      return ((Integer) rootCtx.lookup("tradeLimit")).intValue();
    } catch (NamingException ne) {
      throw new ProcessingErrorException("tradeLimit not found in context");
    } catch (NumberFormatException nfe) {
      throw new ProcessingErrorException("tradeLimit not an integer");
    }
  }

  /**
   * Returns the stock price for a given stock.
   *
   * @param stockSymbol       String Stock symbol
   * @return                  double Stock price
   * @exception               examples.xml.biztalk.ejb.biztrader.ProcessingErrorException
   *                          if there is an error while checking the price
   */
  public double getStockPrice(String stockSymbol) 
    throws ProcessingErrorException 
  {
    try {
      return ((Double) rootCtx.lookup(stockSymbol)).doubleValue();
    } catch (NamingException ne) {
      throw new ProcessingErrorException ("Stock symbol " + stockSymbol + 
                                          " does not exist");
    } catch (NumberFormatException nfe) {
      throw new ProcessingErrorException("Invalid price for stock "+stockSymbol);
    }
  }

  // -----------------------------------------------------------------
  // BizBean implementation

  /**
   * Called by BizTalk Server when a message for this bean is received. 
   * This method processes the BizTalk message payload by executing the trade 
   * defined in the payload.
   *
   * @param message           BizTalk message payload.
   * @exception               RemoteException, ProcessingErrorException
   */
  public void service(IncomingMessage message) 
    throws RemoteException {
    Element n=null;
    try {
      n = (Element) message.getPayloadAsObject();
    } catch (BizException be) {
      System.out.println(be.getMessage());
      return;
    }
    String customer = n.getAttribute("customer");
    String symbol = n.getAttribute("symbol");
    String shares = n.getAttribute("shares");
    String action = n.getAttribute("action");
    System.out.println("Order received by TraderBean:");
    try {
      if (action.equals("sell")) {
        this.sell(customer, symbol, Integer.parseInt(shares));
      } else {
        this.buy(customer, symbol, Integer.parseInt(shares));
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
