/*                                         
 *  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: 10 $
 */

package examples.workflow;

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.IllegalWorkflowTransitionException;
import theory.smart.ebusiness.customer.*;
import theory.smart.ebusiness.session.*;
import javax.naming.*;
import javax.ejb.*;
import java.rmi.RemoteException;
import java.util.*;

/** 
 * Workflow example. This example shows the use of a Business Smart
 * Component that has a workflow associated to it The workflow states
 * and transitions are modeled with Rational Rose.  For this examples,
 * we'll use the EBusinessSession Component. This component has a
 * workflow that guides it through the different stages of an online
 * e-business session. If you look at the Rose model file for the
 * ebusiness.session package, you will find that
 * EBusinessSessionWorkflow has a state diagram associated to it. The
 * workflow logic can be implemented in any way you want; however,
 * Theory Center provides a reference implementation. For the reference
 * implementation, for each component with the BSC.Workflow
 * stereotype, all the states and transitions in the Rose model are
 * generated into a complete state machine by the SmartGenerator, so
 * you can use it immediately, without any hand-coding of the workflow
 * states or transitions. Please note that the SmartGenerator is NOT
 * included in the JumpStart Kit. In this example, we also use the
 * EBusinessSessionManager and show how a "manager" session bean can
 * simplify the usage of an entity bean
 *
 * @see theory.smart.ebusiness.session.EBusinessSession
 * @see theory.smart.ebusiness.session.EBusinessSessionManager
 * @see theory.smart.ebusiness.session.EBusinessSessionWorkflow
 * @see theory.smart.foundation.Workflow */
public class WorkflowExample
{
   static Context ctx = null;	 
   static String user = null;
   static String password = null;
   static String url = "t3://localhost:7501";
   static String customerKey = "TerrySmith";
   
   public WorkflowExample() 
   {
      super();
   }  
   /**
    * This method creates a new guest session. It uses the EBusinessSessionManager to
    * quickly make a session key, create the entity, and set its workflow to "guest"
    * @return EBusinessSession the newly created session
    */
   public EBusinessSession createGuestSession()
   {
      // get an instance of EBusinessSessionManager
      EBusinessSessionManagerHome ebsmHome = null;
      EBusinessSessionManager ebsManager = null;
      try
      {
         // get the manager home from JNDI and create an instance
         ebsmHome = (EBusinessSessionManagerHome) getInitialContext().lookup("theory.smart.ebusiness.session.EBusinessSessionManager");
         ebsManager = ebsmHome.create();
      }
      catch (Exception e)
      {
         exitExample("Could not get create an EBusinessSessionManager", e);
      }
      
      // Create a "guest" session. The initial state will be "guest". The manager will create the session for us.
      // The manager will use an AlphaNumericSequencer component to generate a unique, serial key for our session
      EBusinessSession session = null;
      try
      {
         session = ebsManager.createGuestSession();
      }
      catch (Exception e)
      {
         exitExample("Could not get create a guest EBusinessSession", e);
      }
      
      return session;
   }
   /** 
    * Exit program, displaying the exception
    * @param message the exit message
    * @param e the exception that was raised
    */
   
   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);
      }
      
      System.exit(-1);
   }
   /**
    * Finds or Creates a customer with customerKey
    * @param customerKey  the primary key for out customer
    * @returns customer   a Customer entity bean
    */
   public Customer findOrCreateCustomer(String customerKey)
   {
      // Try to find our customer.
      // If we don't find her/him, create a new one
            
      CustomerHome customerHome = null;
      Customer customer = null;
      
      // First, 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);
      }
      
      // Second, 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 must use a StakeholderPk primary key object
      CustomerPk customerPk = new CustomerPk();
      customerPk.identifier = customerKey;
      
      // since we'll be making numerous remote methods, we need to perform our work within a try..catch to 
      // catch any java.rmi.RemoteExceptions that may get sent to us by the server or the EJBs
      try
      {
         customer = customerHome.findByPrimaryKey(customerPk);
      }
      catch (FinderException fe)
      {
         // Ok, customer does not exist. No sweat, we'll create one.
         try
         {
            customer = customerHome.create(customerPk);
         }
         catch (Exception e)
         {
	    exitExample("Could not create Customer " + customerKey, e);
         }
      }
      catch (RemoteException e)
      {
         exitExample("Got RemoteException while finding", e);
      }
      return customer;
   }
   /**
    * 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
    */
   static 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;
   }
   /**
    * Main driver. The comman line arguments are optional, but if any are supplied,
    * they are interpreted in this order:
    * 
    * customerKey       Customer Key, default "TerrySmith"
    * url               URL such as "t3://localhost:7501" of Server
    * user              User name, default null
    * password          User password, default null
    *
    * You can also get the usage by passing -?
    */
   public static void main(String[] args)
   {
      System.out.println("----------WorkFlowExample running---------");
      WorkflowExample example = new WorkflowExample();
      // Parse the argument list 
      if ((args != null) && (args.length > 0))
      {
         if (args[0].equals("-?"))
         {
            System.out.println("Usage: WorkflowExample <url> <username> <password>");
            return;
         }
         else
         {
            for (int i = 0; i < args.length; i++)
            {
               switch (i)
               {
               case 0 :
                  url = args[i];
                  break;
               case 1 :
                  user = args[i];
                  break;
               case 2 :
                  password = args[i];
                  break;
               default :
               }
            }
         }
      }
      example.run();
   }
   /**
    * This method takes a guest session and moves it thru its workflow
    * @param session the guest EBusinesSession
    */
   public void playWithWorkflow(EBusinessSession session)
   {
      try
      {
         // This session should be on the "guest" state. Let's make sure...
         if (session.getSessionState().equals("guest"))
         {
            System.out.println("Session " + session.getSessionKey() + " should be guest and is in state: " + session.getSessionState());
            System.out.println("--------------------------------------------------------------");
         }
         else
         {
            System.out.println("playWithWorkflow called for a session not in guest state");
            return;
         }
         
         // Take a look at the state diagram. You can find it in the HTML documentation page for this example
         // From here, we can do many things...we can enroll, register, authenticate, etc...
         // Let's try a few transitions...
                  
         // Ok, we decide to enroll
         session.enroll();
         System.out.println("We are enrolling. Session " + session.getSessionKey() + " is now in state: " + session.getSessionState());
         System.out.println("--------------------------------------------------------------");
         
         //...halfway, we decide to quit enrolling (gotta go!)
         session.cancelEnrollment();
         System.out.println("We have cancelled our enrollment process. Session " + session.getSessionKey() + " is now in state: " + session.getSessionState());
         System.out.println("--------------------------------------------------------------");
         // now let's try to do some illegal transitions, to see what happens
         try
         {
            System.out.print("Trying to become guest (again)...");
            session.becomeGuest();
         }
         catch (IllegalWorkflowTransitionException il)
         {
	    System.out.println("and we could not, as it should be...\n\tthe exception looks like this: " + il.getMessage());
	    System.out.println("--------------------------------------------------------------");
         }
         try
         {
	    System.out.print("Trying to disable authentication (and we are not authenticated!)...");
	    session.disableAuthentication();
         }
         catch (IllegalWorkflowTransitionException il)
         {
	    System.out.println("and we could not, as it should be...\n\tthe exception looks like this: " + il.getMessage());
	    System.out.println("--------------------------------------------------------------");
         }
         
         // now, lets try to register, using a customer. We need to create a customer, but that's easy (borrowing code
         // from our previous example...)
         Customer me = findOrCreateCustomer("TerrySmith");
         me.setPassword("foobar");
         
         // now register our EBusinessSession
         session.assignCustomer(me);
         System.out.println("We have registered. Session " + session.getSessionKey() + " is now in state: " + session.getSessionState());
         System.out.println("--------------------------------------------------------------");
         
         // now we can authenticate (using password only, since we are already registered)
         session.authenticate("foobar");
         System.out.println("We have authenticated. Session " + session.getSessionKey() + " is now in state: " + session.getSessionState());
         System.out.println("--------------------------------------------------------------");
         
         // now we do our shopping, etc, and before leaving we log out, to prevent unwanted access!
         session.disableAuthentication();
         System.out.println("Now we logged off. Session " + session.getSessionKey() + " is now in state: " + session.getSessionState());
         System.out.println("--------------------------------------------------------------");
      }
      catch (Exception e)
      {
         exitExample("caught exception in playWithWorkflow", e);
      }
   }
   /**
    * This method runs the example. First, it creates a new EBusiness guest session using the EBusinessSessionManager
    * Then, it moves the workflow of the session around, registering a customer, authenticating, etc
    * Finally, it deletes the session to clean up.
    * @see theory.smart.ebusiness.session.EBusinessSession
    * @see theory.smart.ebusiness.session.EBusinessSessionManager
    * @see theory.smart.foundation.Workflow 
    */
   public void run()
   {
      // create a new EBusinessSession, in "guest" state
      EBusinessSession session = createGuestSession();
      
      // now that we have a guest session, lets move it thru the workflow, testing to see what happens if we try a 
      // wrong transition
      playWithWorkflow(session);
      
      // now delete our session to clean up. (Although we could leave it in the database and come back later and pick it up
      // using either the session id or the customer key...the reader can implement this as a nice exercise!
      try
      {
         System.out.println("Removing session " + session.getSessionKey());
         session.remove();
         System.out.println("--------------------------------------------------------------");
      }
      catch (Exception e)
      {
         exitExample("problem removing session", e);
      }
      System.out.println("Example exits normally");
   }
}
