package examples.businesspolicy;

/*                                         
 *  T H E                                     Copyright (c) The Theory Center,
 *                                            Inc. 1997-1999. All Rights Re-
 * |||||  ||                                  served. Unpublished rights re-
 *   ||   ||                                  served under the copyright laws
 *   ||   ||||    |||    |||   |||||  |  ||   of the United States. The soft-
 *   ||   ||  |  |   |  ||  |  ||  |  |  ||   ware contained on this media is
 *   ||   ||  |  |||||  ||  |  ||     |  ||   proprietary to and embodies the
 *   ||   ||  |  |      ||  |  ||      ||||   confidential technology of
 *   ||   ||  |   |||    |||   ||         |   The Theory Center. The possession
 *                                     ||||   or receipt of this information
 *                                            does not convey any right to dis-
 *  |||                   ||                  close its contents, reproduce it,
 * ||  |                  ||                  or use,  or license the use, for
 * ||      |||   ||||    ||||   |||   |||||   manufacture or sale, the informa-
 * ||     |   |  ||  |    ||   |   |  ||  |   tion or anything described
 * ||     |||||  ||  |    ||   |||||  ||      therein. Any use, disclosure, or
 * ||  |  |      ||  |    ||   |      ||      reproduction without The Theory
 *  |||    |||   ||  |    ||    |||   ||      Center's prior written permission
 *                                            is strictly prohibited.
 *
 *
 * $JustDate:  8/17/99 $ $Revision: 13 $
 */

import java.util.*;
import java.rmi.*;
import javax.ejb.*;
import javax.naming.*;
import theory.tracer.*;
import theory.smart.axiom.units.*;
import theory.smart.axiom.util.*;
import theory.smart.axiom.messaging.*;
import theory.smart.axiom.contact.*;
import theory.smart.axiom.workflow.*;
import theory.smart.axiom.accounting.*;
import theory.smart.foundation.*;
import theory.smart.ebusiness.item.*;
import theory.smart.ebusiness.customer.*;

/**
 *
 * This example demonstrates the concept of "Pluggable Methods",
 * better known as policies. When you create your components, you will
 * realize that many times you want to alter the component behaviour
 * based on external conditions that you can not evaluate at
 * development time. Reusability, extensibility and rapid development
 * and enhancement are typical problems that can be solved using
 * policies. BusinessPolicy is Theory Center's implementation of the Policy and 
 * Strategy design patterns.
 *
 * Using this concepts allows you to replace the default policy at runtime.  The
 * policy is stored as a property for the item.
 * In this example we will use an item component. The item component has a
 * default pricing policy. The item's price can be calculated in two ways:  By
 * supplying only a quantity, you can have the price be calculated based on the
 * default policy; By supplying a pricing policy in addition to a quantity, the
 * item's price can be calculated using the new pricing policy. You can replace
 * the pricing policy to alter the way the price is calculated for the item.
 * This means that you can modify the behaviour of the item by plugging in a
 * method that calculates the price the way you want.
 *
 * The example creates an item.  It Then, sets the SeniorCitizenDiscountPolicy
 * as the default pricing policy for the item.  Then, the item's price is
 * calculated using the default  policy. Finally,it modifies the item quantity
 * and once again, calculates the price; this time using the
 * AprilFoolsDiscountPolicy policy.
 *
 * To better understand this example it would be great if you go through the 
 * Axiom example first 
 *
 * @see examples.axiom.AxiomExample
 * @see theory.smart.ebusiness.item.Item
 * @see theory.smart.ebusiness.item.ItemPriceCalculationPolicy
 * @see theory.smart.foundation.BusinessPolicy
 * @see examples.businesspolicy.AprilFoolsDiscountPolicy 
 * @see examples.businesspolicy.SeniorCitizenDiscountPolicy 
 * @see theory.smart.axiom.units.Quantity
 * @see theory.smart.axiom.units.Price
 *
 * @author Copyright (c)1997-1999 by The Theory Center, Inc. All Rights Reserved.
 * */

public class BusinessPolicyExample
{
   Context ctx = null;
   String user = null;
   String password = null;
   String url = "t3://localhost:7501";
   String customerKey = "TerrySmith";
	  
   public static final String HOME_NAME = "theory.smart.ebusiness.item.Item";
   
   
   /**
	*
	* BusinessPolicyExample default constructor.
	*
	*/
   public BusinessPolicyExample()
   {
	  super();
   }   
   /**
	*
	* Displays the description and price of an item.
	* This method also illustrates the use of the Price component
	*
	*
	* @see theory.smart.axiom.units.Price
	* @param item The item that you want to display
	*
	*/
   public void displayItemDetails(Item item){
	  
	  String itemDescription = null;
	  Price itemPrice = null;
	  double price = 0;
	  
	  try
	  {
		 itemDescription = item.getDescription();
		 itemPrice = item.getPrice();
		 price = itemPrice.getValue();
	  }
	  catch (RemoteException re)
	  {
		 exitExample("Failed to retrieve item price", re);
	  }
	  
	  System.out.println(itemDescription + " is $" + price + " per lb.");
	  System.out.println("---------------------------------------------");
	  System.out.println("");
   }   
   /**
	*
	* Display the message and the exception and terminate the
	* the program
	* 
	* @param message The message to display upon termination
	* @param e The exception thrown or null if no exception was thrown
	*
	*/
   public void exitExample(String message, Exception e)
   {
	  if (message != null)
	  {
		 System.out.println("Example exited: " + message);
	  }
	  if (e != null)
	  {
		 System.out.println("Exception thrown: " + e);
		 e.printStackTrace(System.out);
	  }
   }   
   /**
	*
	* Finds or Creates a customer with the given customerKey. 
	* 
	* @param customerKey the key for the customer
	* @return the customer's entity bean
	*
	*/
   public Customer findOrCreateCustomer(String customerKey)
   {
	  // Try to find our customer.
	  // If we don't find the customer, create a new one
			
	  CustomerHome customerHome = null;
	  Customer customer = null;
	  
	  //
	  // Get the customer's home using JNDI	
	  //
	  try
	  {
		 customerHome = (CustomerHome) getInitialContext().lookup("theory.smart.ebusiness.customer.Customer");
	  }
	  catch (Exception e)
	  {
		 exitExample("Could not get Customer Home", e);
	  }
	  
	  //
	  // Try to find customer using primary key. We need to use a primary key object. 
	  // Since the Customer entity EJB extends the Stakeholder entity EJB, 
	  // we will use a StakeholderPk primary key object
	  //
	  CustomerPk customerPk = new CustomerPk();
	  customerPk.identifier = customerKey;

	  
	  //
	  // Since we'll be messaging numerous remote methods, we need to perform our work 
	  // within a try catch to catch any java.rmi.RemoteExceptions that may get thrown
	  //
	  System.out.println("--------------------------------------------------------------");
	  try
	  {
		 customer = customerHome.findByPrimaryKey(customerPk);
		 System.out.println("Found customer " + customerKey);
		 System.out.println("--------------------------------------------------------------");
	  }
	  catch (FinderException fe)
	  {
		 //
		 // Ok, customer does not exist. No sweat, we'll create one.
		 //
		 try
		 {
			customer = customerHome.create(customerPk);
			System.out.println("Did not find customer " + customerKey + ", customer has been created");
			System.out.println("--------------------------------------------------------------");
		 }
		 catch (Exception e)
		 {
			exitExample("Could not create Customer " + customerKey, e);
		 }
	  }
	  catch (RemoteException e)
	  {
		 exitExample("Got RemoteException while finding", e);
	  }
	  return customer;
   }
   /**
	*
	* Obtains the item home from JNDI, it  searches for an item with the
	* given primary key. If the item is found it is returned, otherwise
	* a new item with the given primary key is created and returned.
	*
	* @param identifier A unique identifier for the item (SKU)
	* @param supplier The item supplier
	* @param version The catalog version of this item
	*
	*
	* @return The item with the given primary key
	*
	*/
   public Item findOrCreateItem( String identifier, String supplier, String version )
   {
	  ItemHome itemHome = null;
	  Item item = null;

	  //
	  // Get item home
	  //
	  try
	  {
		 itemHome = (ItemHome) getInitialContext().lookup(HOME_NAME);
	  }
	  catch (Exception e)
	  {
		 exitExample("Failed to get Item Home", e);
	  }


	  ItemPk itemKey = new ItemPk(supplier, identifier, version);
	  try
	  {
		 //
		 // Try to find the item
		 //
		 item = itemHome.findByPrimaryKey(itemKey);
	  }
	  catch (FinderException fe)
	  {
		 //
		 // Could not find the item in DB, create a new one
		 //
		 try
		 {
			item = itemHome.create(itemKey);

			Price itemPrice = PriceHome.create();
			itemPrice.setValue(5.99);
			item.setPrice(itemPrice);

			item.setDescription("Double Baked Pinto Beans");
		 }
		 catch (Exception e)
		 {
			exitExample("Failed to create item", e);
		 }
	  }
	  catch (RemoteException re)
	  {
		 exitExample("Got RemoteException while finding", re);
	  }
	  return item;
   }
   /**
	*
	* Gets an initial context for the current user, password and url.
	*
	* @return		    Context
	* @exception		    java.lang.Exception if there is
	*			    an error in getting the Context
	*/
   public Context getInitialContext() throws Exception
   {
	  if (ctx == null)
	  {
		 Properties p = new Properties();
		 p.put(Context.INITIAL_CONTEXT_FACTORY,
			   "weblogic.jndi.WLInitialContextFactory");
		 p.put(Context.PROVIDER_URL, url);
		 if (user != null)
		 {
			p.put(Context.SECURITY_PRINCIPAL, user);
			if (password == null)
			   password = "";
			p.put(Context.SECURITY_CREDENTIALS, password);
		 }
		 ctx = new InitialContext(p);
	  }
	  return ctx;
   }
   /**
	* The main method of the Business Policy example.
	* It instantiates and runs a new BusinessPolicy Example
	*
	* @param argv The command line arguments
	*
	*/
   public static void main(String[] argv)
   {
	  	  System.out.println("----------BusinessPolicyExample running---------");

	  	  new BusinessPolicyExample().run();
   }
   /**
	*
	* This method is the sequence of the example:
	* 1.- Find or create a new Item with the given primary key
	* 2.- Create an quantity belonging
	* 3.- Create a new SeniorCitizenDiscountPolicy
	* 4.- Calculate the price using the above quantity and policy
	* 5.- Change the count in the quantity
	* 6.- Create a new AprilFoolsDiscountPolicy
	* 7.- Calculate the price using the new quantity and policy
	*
	* @see examples.businesspolicy.AprilFoolsDiscountPolicy
	* @see examples.businesspolicy.SeniorCitizenDiscountPolicy
	* @see theory.smart.axiom.units.Quantity
	*
	*/
   public boolean run()
   {

	  String supplier = "BeanTown Inc.";
	  String identifier = "BTW-002";
	  String version = "0";

  	  Customer customer = null;

	  // find (or create) our customer
	  customer = findOrCreateCustomer(customerKey);

	  // Lets give our customer a name, shall we?
	  try
	  {
		 customer.setFirstName("Terry");
		 customer.setLastName("Smith");
	  }
	  catch (Exception e)
	  {
		 exitExample("Could not set customer's name", e);
	  }

	  // now that we have a customer, let's adjust the price of an item for him

	  Item item = findOrCreateItem(supplier, identifier, version);

   	  System.out.println("Customer "+ customerKey + "is a senior citizen.");
   	  System.out.println("We will set his Default Pricing policy to the SeniorCitizenDiscountPolicy");
	  System.out.println("");
	  System.out.println("Without any discounts...");
	  displayItemDetails(item);
	  
	  Quantity itemQuantity = QuantityHome.create();
	  itemQuantity.setCount(1);
	  
	  // add SeniorCitizensDiscountPolicy pricing policy as default
	  // price calculation policy of the item.
	  SeniorCitizenDiscountPolicy sc = new SeniorCitizenDiscountPolicy();
	  try
	  {
		 System.out.println("");
		 System.out.println("---> Adding SeniorCitizenDiscountPolicy as the Default Pricing Policy...");
		 item.setDefaultItemPriceCalculationPolicy(sc);
		 System.out.println("");
		 System.out.println("Default Pricing policy is set.");
		 
		 System.out.println("--->Changing price based on the Default Pricing Policy...");
		 Price p1 = item.calculatePrice(itemQuantity, customer);
		 item.setPrice(p1);
	  }
	  catch (RemoteException re)
	  {
		 exitExample("Failed to add first business policy", re);
	  };
	  
	  displayItemDetails(item);
	  
	  
	  itemQuantity.setCount(200);
	  
	  //calculate price with  AprilFoolsDiscountPolicy pricing policy
	  // without adding it as a pricing policy for this item.
	  AprilFoolsDiscountPolicy af = new AprilFoolsDiscountPolicy();
	  try
	  {
		 System.out.println("Today is April 1st.  Everyone will get a special discount!");
		 System.out.println("");
		 System.out.println("---> Changing price based on the AprilFoolsPricingPolicy...");
		 Price p2 = item.calculatePrice(af, itemQuantity, customer);
		 item.setPrice(p2);
	  }
	  catch (RemoteException re)
	  {
		 exitExample("Failed to add second business policy", re);
	  };
	  
	  displayItemDetails(item);

	  System.out.println("Example exits normally.");
	  return true;
   }            
}      