Sample Program

Today you will write a sample application that demonstrates the use of the JNDI APIs. The sample application shows the use of a server application component that registers with WebLogic Server's naming service and a client application that uses JNDI to look up and interact with the server application component. The sample application shows the interaction between a customer and waiter in a restaurant. You will incrementally build the restaurant application's components over the next days' lessons, which cover Enterprise JavaBeans (EJBs). The actual designing of the restaurant application is discussed in the next days. For this application, you will write a simple set of Java classes that perform the role of the server component and client application separately from any support classes that may be required. Hence, you will focus on the use of the JNDI APIs by the server component and the client application and not on the actual design of the server component of the application.

Because the sample program covers the interactions between a customer and a waiter in a restaurant, the central classes of the sample application are modeled on these entities. The class design consists primarily of the Restaurant, Customer, and WaiterImpl classes implementing the services defined in the WaiterInterface interface.

Put simply, a customer looks up the list of restaurants in a directory (such as a phone book), chooses one restaurant, and finds its location. In this case, the restaurant is The_Taste_Of_Sams restaurant. The Restaurant class has a WaiterInterface object bound in WebLogic Server's naming service ready to service the customer modeled by the Customer class. Once the customer enters the restaurant, the Customer class looks up the WaiterInterface object from WebLogic Server's naming service using the JNDI API, obtains a reference to the WaiterInterface object, and begins its interaction with it till the time the customer is present in the restaurant. Simple functionality, isn't it? For brevity's sake, you will not cover the support classes because the same problem statement is taken up in tomorrow's lesson, where the entire design is discussed again.

Server-side

Now consider the source code for the core classes and interfaces of this application. The first piece of code that you will write is for the service methods of the waiter in the WaiterInterface interface (Listing 9.1). These methods essentially define the life cycle of the interaction between the customer and the waiter, starting from getMenu() all the way down to the final step, getCheck().

Listing 9.1 WaiterInterface.java
 /******************************************************************************   * Class Name   : WaiterInterface.java   * Description  : Interface for Waiter class. Defines the methods that can be   *                performed by the Waiter class.   * @author Mandar S. Chitnis, Lakshmi AM, Pravin S. Tiwari.       @version 1.1   * Copyright (c) by Sams Publishing. All Rights Reserved. *******************************************************************************/ package com.sams.learnweblogic7.jndi; import java.util.*; public interface WaiterInterface extends java.io.Serializable {        public MenuList getMenu();        public void getOrder(MenuItem orderedItem, int quantity);        public void confirmOrder();        public ChefInterface getChefFromChefPool();        public Vector serveCookedItem();        public float getCheck(); } 

The WaiterImpl class (Listing 9.2) implements the methods in the WaiterInterface interface. The WaiterImpl class uses support classes to create the functionality of these methods. For the purpose of studying JNDI, you do not need to see the details of this class. For your purposes, WaiterImpl is just a server application component (which uses support classes) that will be registered in the WebLogic Server's naming service.

Listing 9.2 WaiterImpl.java
 /******************************************************************************   * Class Name   : WaiterImpl.java   * Description  : Implements all methods of the WaiterInterface.java class   * @author Mandar S. Chitnis, Lakshmi AM, Pravin S. Tiwari.       @version 1.1   * Copyright (c) by Sams Publishing. All Rights Reserved. *******************************************************************************/ package com.sams.learnweblogic7.jndi; import java.util.*; public class WaiterImpl implements WaiterInterface {        //defining private and public variables, for the list of items ordered        //by client, and items cooked by chef        private Vector orderedItemsList = new Vector();        private Vector cookedItems = new Vector();        public String tempString = "Trial String";        //method called by client to get a list of Menu items.        public MenuList getMenu(){               return MenuList.getMenu();        }        //method called by client to get the order.        //The client gets the menu item id from the menu list,        //and also specifies the number of items.        public void getOrder(MenuItem orderedItem, int quantity){               orderedItemsList.addElement(new Order(orderedItem, quantity));        }        //the client calls this method to confirm his order.        //When he does this, the waiter requests for a chef available from        //the chef pool, and sends the item to be prepared to the chef.        //The chef returns the cooked item. The waiter then collects all        //the cooked items into his tray (the global vector),        //returns the cook into the cook pool.        public void confirmOrder(){               CookedItemImpl currentCookedItem;               MenuItem menuItemToBeProcessed;               Enumeration orderedItemsEnum = orderedItemsList.elements();               while(orderedItemsEnum.hasMoreElements())               {                      ChefInterface currentChef = getChefFromChefPool();                      menuItemToBeProcessed =                              ((Order)orderedItemsEnum.nextElement()).getItem();                      currentCookedItem =                              currentChef.cookItem(menuItemToBeProcessed);                      cookedItems.addElement(currentCookedItem);                      PoolClass.returnChef(currentChef);               }        }        //called by the waiter to get a chef from the chef pool        public ChefInterface getChefFromChefPool(){               return PoolClass.getChef();        }        //performed by the waiter after all the items are cooked,        //and collected in the vector, and then serves the client.        public Vector serveCookedItem(){               return cookedItems;        }        //called by the client, to get his check.        public float getCheck(){               float checkSum = 0;               Enumeration orderedItemsEnum = orderedItemsList.elements();               while(orderedItemsEnum.hasMoreElements())               {                      Order individualCurrOrder =                              (Order)orderedItemsEnum.nextElement();                      checkSum +=                              (individualCurrOrder.getItem()).getItemPrice()                              *individualCurrOrder. getQty();               }               return checkSum;        } } 

So who does the registering of the WaiterImpl server component in WebLogic Server's naming service? The registering of the WaiterInterface object that is, the WaiterImpl class is carried out by the Restaurant class. You need to study the Restaurant class because the JNDI APIs come into play here; see Listing 9.3.

Listing 9.3 Restaurant.java
 /******************************************************************************   * Class Name   : Restaurant.java   * Description  : Binds waiters when the customer enters the Restaurant for the   *                first time.   * @author Mandar S. Chitnis, Lakshmi AM, Pravin S. Tiwari.       @version 1.1   * Copyright (c) by Sams Publishing. All Rights Reserved. *******************************************************************************/ package com.sams.learnweblogic7.jndi; import javax.naming.*; import java.util.*; import java.io.*; import java.text.*; public class Restaurant {        private static boolean waitersBound=false;        public String enterRestaurant(){               if(!waitersBound){                      bindWaiters();               }               return "Welcome To The Taste of Sams";        }        public void bindWaiters(){       Context ctx = null;       try {         Hashtable env = new Hashtable();         env.put(           Context.INITIAL_CONTEXT_FACTORY,           "weblogic.jndi.WLInitialContextFactory"         );         ctx = new InitialContext(env);         System.out.println("Initial context created");         WaiterImpl WaiterObj = new WaiterImpl();         WaiterObj.tempString = "This is inside the restaurant now";         String bindName = "WaiterObj";         // Create a unique String object (bindStr) and bind it to (bindName)         try {           ctx.bind(bindName, WaiterObj);           System.out.println("Bound '" + WaiterObj + "' to '"+bindName+"'                   for the first time.");         }         catch (NameAlreadyBoundException e) {           // Binding already exists.           // As for the createSubcontext() method, this exception is not thrown           // by the WebLogic implementation of Context when the name is aleady           // bound to an identical object. However, you have created a unique           // string by including the date and time here.           // Run the example more than once in the same           // WebLogic Server session and the exception will be thrown.           System.out.println("Overriding old binding. Rebinding '" +                              WaiterObj +"' to '"+bindName+"'.");           // Force a new binding           ctx.rebind(bindName, WaiterObj);         }       }       catch (NamingException e) {         System.out.println(e.toString());       }       finally {         if (ctx != null) {           try {             ctx.close();           } catch (NamingException e) {             System.out.println("Failed to close context due to: " + e);           }         }       }        }//end of bindWaiters } 

Listing 9.3 shows the two methods in the Restaurant class, enterRestaurant() and bindWaiters(). The enterRestaurant() method is called by the Customer class when the customer enters the restaurant.

 public String enterRestaurant(){         if(!waitersBound){               bindWaiters();        }        return "Welcome To The Taste of Sams"; } 

The enterRestaurant() method checks the waiterBound Boolean flag to verify whether the WaiterInterface object is bound to the naming service. If not, the bindWaiters() method is called. Now study the JNDI API calls used in this method.

The first API call is to initialize WebLogic Server's context factory by setting the appropriate values in the hash table used in the creation of the InitialContext object.

        public void bindWaiters(){        Context ctx = null;       try {         Hashtable env = new Hashtable();         env.put(           Context.INITIAL_CONTEXT_FACTORY,           "weblogic.jndi.WLInitialContextFactory"         );         ctx = new InitialContext(env);         System.out.println("Initial context created"); ... } 

After the context is initialized, the Restaurant class instantiates a WaiterInterface object and binds it to the naming service using the bind() method of the InitialContext object. The name used to bind the WaiterInterface object to the naming service is WaiterObj.

 WaiterImpl WaiterObj = new WaiterImpl();  WaiterObj.tempString = "This is inside the restaurant now"; String bindName = "WaiterObj";         // Create a unique String object (bindStr) and bind it to (bindName)         try {           ctx.bind(bindName, WaiterObj);           System.out.println("Bound '" + WaiterObj + "' to '"+bindName+"'                   for the first time.");         }         catch (NameAlreadyBoundException e) {               ...        } 

The bind() method throws the NameAlreadyBoundException exception if an object with the same name that is, WaiterObj is bound in the naming service. If an object with the same name exists, you overwrite the existing object reference in the naming service with the new object reference using the rebind() method call, as shown in the following code snippet.

 ...        }         catch (NameAlreadyBoundException e) {           // Binding already exists.           // As for the createSubcontext() method, this exception is not thrown           // by the WebLogic implementation of Context when the name is already           // bound to an identical object. However, you have created a unique           // string by including the date and time here. Run the example more than           // once in the same WebLogic Server session           // and the exception will be thrown.           System.out.println("Overriding old binding. Rebinding '" +                              WaiterObj +"' to '"+bindName+"'.");           // Force a new binding           ctx.rebind(bindName, WaiterObj);       } 

At the end, the Restaurant class frees up the resources used by the InitialContext object using the close() method.

 finally {          if (ctx != null) {           try {             ctx.close();           } catch (NamingException e) {             System.out.println("Failed to close context due to: " + e);           }         }       } 

Client Side

Today's lesson has covered the server-side use of the JNDI API, where server components register with the naming service to advertise their services. Now look at the more important and widely used client-side part of the JNDI API. The Customer class extensively uses the client-side JNDI API for naming as well as directory services.

As discussed earlier, the Customer class looks up a directory service to select a Restaurant class. Using a directory service such as LDAP is not possible for this sample application. Hence, you use a .prop properties file like a phone book to store information about the different restaurants.

You use a special freeware set of Java classes, the FSContext package, to simulate the directory services on the contents of the properties file. The freeware set of Java classes can be downloaded from http://java.sun.com/products/jndi/index.html#DOWNLOAD12.

Click the Continue button, which takes you to the Terms and Conditions page. Accept the terms and conditions by clicking the Accept button. Finally, click the link for FS Context (File system service provider, 1.2 beta 3 release) and download the file named fscontext-1_2-beta3.zip. The fscontext-1_2-beta3.zip file contains the two Java archive files fscontext.jar and providerutil.jar.

The contents of the .prop properties file appear in Listing 9.4.

Listing 9.4 RestaurantProps.prop
 RestaurantNames=The_Taste_Of_Sams,Mediterranean_Excellence,         Indian_Shahi_Khazana,FoodSeco The_Taste_Of_Sams_City=Chicago The_Taste_Of_Sams_State=Illinois The_Taste_Of_Sams_Type=Fastfood 

The list of restaurants is the value of the RestaurantNames property. The list contains the names The_Taste_Of_Sams, Mediterranean_Excellence, Indian_Shahi_Khazana, and FoodSeco. The details for each restaurant are given after this: the city, state, and specialty of the restaurant. These are the attributes for the restaurant that will be searchable using the FSContext directory-service-simulation Java classes. Listing 9.5 shows the code for the Customer class.

Listing 9.5 Customer.java
 /******************************************************************************   * Class Name   : Customer.java   * Description  : Customer of the restaurant. Does a lookup for the name of   *                the restaurant. Then gets a waiter, orders dishes, and then   *                finally, gets the check.   * @author Mandar S. Chitnis, Lakshmi AM, Pravin S. Tiwari.       @version 1.1   * Copyright (c) by Sams Publishing. All Rights Reserved. *******************************************************************************/ import com.sams.learnweblogic7.jndi.*; import javax.naming.*; import javax.naming.directory.*; import java.util.*; import java.io.*; import java.text.*; public class Customer{        private static final String DESIGN_DASH =                "--------------------------------------------------------------";   public static void main(String[] args) {       //create a context object. First create env Hashtable and pass the       //Hashtable as a parameter to the constructor.       Context ctx = null;       try {         Hashtable env = new Hashtable();         env.put(Context.INITIAL_CONTEXT_FACTORY,                 "weblogic.jndi.WLInitialContextFactory");         ctx = new InitialContext(env);         System.out.println("Created new initial context");           Hashtable restaurantEnv = new Hashtable();           restaurantEnv.put(Context.INITIAL_CONTEXT_FACTORY,                   "com.sun.jndi.fscontext.RefFSContextFactory");           restaurantEnv.put(Context.PROVIDER_URL,"file:/c:/book");           Context initCtx = new InitialDirContext(restaurantEnv);           System.out.println("Initial Directory context created");           try{             File restPropsFile = (File)initCtx.lookup("code" + File.separator +                     "Jndi" + File.separator + "Client" + File.separator +                     "RestaurantProps.prop");                      FileInputStream restPropsFileInputStream = new                              FileInputStream(restPropsFile);                      Properties restaurantProps = new Properties();                      restaurantProps.load(restPropsFileInputStream);                      //decided to go to the restaurant - "The taste of Sams"                      String restaurantCity =                              restaurantProps.                              getProperty("The_Taste_Of_Sams_City");                      System.out.println(restaurantCity);                      String restaurantState =                              restaurantProps.                              getProperty("The_Taste_Of_Sams_State");                      System.out.println(restaurantState);                      String restaurantType =                              restaurantProps.                              getProperty("The_Taste_Of_Sams_Type");                      System.out.println(restaurantType);               }               catch(Exception e){                      e.printStackTrace();               }        /**          * Since the client enters the restaurant,          * to enter, create a restaurant object.          * Then enter the restaurant by calling the enterRestaurant method.          * Perform a context lookup for the Waiter Object.          * Then perform a lookup for the waiter object.        **/          String bindName = "WaiterObj";          try {               Restaurant samsRestaurant = new Restaurant();               String welcomeString = samsRestaurant.enterRestaurant();               System.out.println(DESIGN_DASH);               System.out.println(welcomeString);               WaiterImpl thisWaiterObj = (WaiterImpl)ctx.lookup(bindName);               //once the waiter object is obtained,               //request the waiter to get the menu list.               MenuList myMenuList = thisWaiterObj.getMenu();               System.out.println(DESIGN_DASH);               System.out.println("Menulist returned");               //ordering items 1, 2 and 3.               //To do that, picking up the items from the menulist first.               MenuItem orderedItem1 = (MenuItem)myMenuList.get("1");               MenuItem orderedItem2 = (MenuItem)myMenuList.get("2");               MenuItem orderedItem3 = (MenuItem)myMenuList.get("3");               thisWaiterObj.getOrder(orderedItem1, 1);               thisWaiterObj.getOrder(orderedItem2, 2);               thisWaiterObj.getOrder(orderedItem3, 3);               //confirming the order               thisWaiterObj.confirmOrder();               //once the waiter has confirmed the order,               //the waiter serves the items.               Vector cookedItems = thisWaiterObj.serveCookedItem();               System.out.println(DESIGN_DASH);               System.out.println("The served items are:");               Enumeration servedItemsEnum = cookedItems.elements();               while(servedItemsEnum.hasMoreElements()){                      CookedItemImpl servedItem =                              (CookedItemImpl)servedItemsEnum.nextElement();                      System.out.println(DESIGN_DASH);                      System.out.println("Item Name :"+servedItem.getItemName());                      System.out.println                              ("Serving Size :"+servedItem.getServingSize());                      System.out.println("Taste of Item                              :"+servedItem.getTaste());                      System.out.println                              ("Ingredients of Item                              :"+servedItem.getIngredients());                      System.out.println                              ("Temperature of Item                              :"+servedItem.getTemperature());               }               //After serving, the client requests the check.               float bill = thisWaiterObj.getCheck();               System.out.println("Your bill is $"+bill);          }          catch (NamingException e) {               System.out.println(e.toString());          }     }     catch (NamingException e) {               System.out.println(e.toString());        }        finally {               if (ctx != null) {               try {                      ctx.close();               } catch (NamingException e) {                      System.out.println("Failed to close context due to: " + e);               }        }   }  } } 

Following the steps in the life cycle of a JNDI application, the Customer class initializes the WebLogic Server's context factory in order to interact with WebLogic Server's naming service.

 try {          Hashtable env = new Hashtable();         env.put(           Context.INITIAL_CONTEXT_FACTORY,           "weblogic.jndi.WLInitialContextFactory"         );         ctx = new InitialContext(env);         System.out.println("Created new initial context"); ... } 

After creating the initial context for the naming service, the Customer class creates a directory context to access the directory services provided by the FSContext Java classes package.

 Hashtable restaurantEnv = new Hashtable();  restaurantEnv.put(Context.INITIAL_CONTEXT_FACTORY,         "com.sun.jndi.fscontext.RefFSContextFactory"); restaurantEnv.put(Context.PROVIDER_URL,"file:/c:/book"); Context initCtx = new InitialDirContext(restaurantEnv); System.out.println("Created new initial context"); try{        File restPropsFile =                (File)initCtx.lookup("code" + File.separator + "Jndi" +                File.separator +                "Client" + File.separator + "RestaurantProps.prop");        FileInputStream restPropsFileInputStream =                new FileInputStream(restPropsFile);        Properties restaurantProps = new Properties();        restaurantProps.load(restPropsFileInputStream);        //decided to go to the restaurant - "The taste of Sams"        String restaurantCity =                restaurantProps.                getProperty("The_Taste_Of_Sams_City");        System.out.println(restaurantCity);        String restaurantState =                restaurantProps.                getProperty("The_Taste_Of_Sams_State");        System.out.println(restaurantState);        String restaurantType =                restaurantProps.                getProperty("The_Taste_Of_Sams_Type");        System.out.println(restaurantType); } catch(Exception e){        e.printStackTrace(); } 

For creating the directory context, Customer class creates an InitialDirContext object and passes it the values of the FSContext directory service in the restaurantEnv hash table. The context factory for the directory service is com.sun.jndi.fscontext.RefFSContextFactory and the provider URL is file:/c:/book. After creating the directory context, the Customer class performs a lookup in the directory service for the file system to obtain the object associated with the RestaurantProps.prop properties file. The directory service returns the File object that represents the handle to the RestaurantProps.prop file. The Customer class uses the File object to read the properties, chooses to visit the The_Taste_Of_Sams restaurant, and reads these properties. The preceding code snippet shows the use of the FSContext directory services to locate a restaurant.

The next step for the Customer class is to enter the restaurant using the enterRestaurant() method. This method in the Restaurant class, as you recall, binds the WaiterInterface object to the naming service if the object is not already bound.

After the naming context is initialized, the Customer class queries WebLogic Server's naming service to obtain the reference to the WaiterInterface object using the lookup() method on the IntialContext object of the naming service, as shown in this code snippet:

 String bindName = "WaiterObj";  try {      Restaurant samsRestaurant = new Restaurant();      String welcomeString = samsRestaurant.enterRestaurant();      System.out.println(DESIGN_DASH);      System.out.println(welcomeString);      WaiterInterface thisWaiterObj =              (WaiterInterface)ctx.lookup(bindName);      //once the waiter object is obtained,      //request the waiter to get the menu list. 

Now that the Customer class has the WaiterInterface object reference with it, the Customer class invokes the different service methods of the WaiterInterface interface implemented by the WaiterImpl class.

This completes your study of the client-side JNDI APIs used by the Customer class. You will now compile all the classes of the restaurant application.

Compile the Program

Use the provided compile.bat batch file to compile the classes and interfaces of the restaurant application. Because you are using the FSContext directory service packages in the application, the compile.bat file sets the location of the Java archive files fscontext.jar and providerutil.jar in the CLASSPATH.

The items that are compiled by the batch file include the Restaurant and WaiterImpl classes, the WaiterInterface interface, and the Customer JNDI client Java classes. The batch file compiles the files of the restaurant application located in the C:\book\code\Jndi\src\*.java directory.

The command for compiling is

 javac  d C:\bea\user_domains\mydomain\applications\myWebApp\WEB-INF\classes            *.java C:\book\code\Jndi\src\.java 

After you generate the .class files for the source code, the next step is to deploy the application.

Deploy the Program

The only setting required to deploy the application is to include the Java archive files of the FSContext directory service package that the application will be using. Add the location of the fscontext.jar and providerutil.jar Java archive files to the CLASSPATH before executing the restaurant application.

Execute the Program

Finally, execute the restaurant application to see the output. Because the server component is registered by the Restaurant application when the Customer class invokes the enterRestaurant() method, you need only to execute the Customer class using this command:

 java Customer  

After executing the Customer class, you should see the same output as shown in Figure 9.7.

Figure 9.7. The output of the Customer class in the command-prompt window.

graphics/09fig07.jpg



Sams Teach Yourself BEA WebLogic Server 7. 0 in 21 Days
Sams Teach Yourself BEA WebLogic Server 7.0 in 21 Days
ISBN: 0672324334
EAN: 2147483647
Year: 2002
Pages: 339

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net