Sams Teach Yourself BEA WebLogic Server 7.0 in 21 Days
The stateless session bean builds on the restaurant example application that you developed yesterday. In that example, you built the Waiter as a stateful session bean associated with a Customer client application. The ChefImpl class was built as a normal Java class that implemented the interface ChefInterface. Today you will revamp the chef classes from the restaurant application and develop them as a stateless session bean. This is because, in the requirements, you defined that the waiters could forward customer orders or selections to any of the available chefs for processing (cooking) and could retrieve the cooked items from the chefs. This represents a classical case of stateless session bean behavior. The rest of the classes of yesterday's restaurant application will stay the same; you will modify only the chef-related classes and interfaces. You will group the chef classes and interfaces in the com.sams.learnweblogic7.ejb. stateless package. Figure 11.3 diagrams the relevant classes and interfaces. Figure 11.3. Class diagram of the classes and interfaces for the chef stateless session bean in the restaurant application.Chef Classes and Interfaces
You will model the chef as a stateless session bean. Hence, you will create the following classes and interfaces:
Now look at the source code for the classes and interfaces for the chef functionality. Because the rest of the restaurant application is the same, you will not be listing the code for the other classes. You can reuse the same code that was developed yesterday. The only other change required to yesterday's code is to the WaiterBean class, which instantiates a ChefInterface object in order to interact with it. Listing 11.1 shows the ChefInterface remote interface. Listing 11.1 ChefInterface.java
/****************************************************************************** * Class Name : ChefInterface.java * Description : Remote Interface for the ChefBean bean. * Defines method cookItem() for the ChefBean bean. * This method is called by the Waiter bean. * @author Mandar S. Chitnis, Lakshmi AM, Pravin S. Tiwari. @version 1.1 * Copyright (c) by Sams Publishing. All Rights Reserved. ******************************************************************************/ package com.sams.learnweblogic7.ejb.stateless; import java.rmi.RemoteException; import javax.ejb.EJBObject; public interface ChefInterface extends EJBObject { /** * This method is called by the waiter to cook the item. * * @param orderedItem MenuItem object ordered item * @return object CookedItem */ public CookedItemImpl cookItem(MenuItem orderedItem) throws RemoteException; } As you can see, the ChefInterface still defines the cookItem() method. The only difference from the ChefInterface that you developed in yesterday's application is that the ChefInterface is now defined as the remote interface of the ChefBean stateless session bean and hence extends the EJBObject interface. Also, the cookItem() method now throws the exception RemoteException. Next you will write the home interface for the chef session bean; see Listing 11.2. Listing 11.2 ChefHome.java
/****************************************************************************** * Class Name : ChefHome.java * Description : Home Interface for the ChefBean bean. * Defines method create() for the ChefBean bean * per the EJB specifications. * @author Mandar S. Chitnis, Lakshmi AM, Pravin S. Tiwari. @version 1.1 * Copyright (c) by Sams Publishing. All Rights Reserved. ******************************************************************************/ package com.sams.learnweblogic7.ejb.stateless; import java.rmi.RemoteException; import javax.ejb.CreateException; import javax.ejb.EJBHome; /** * This is the home interface for the ChefBean.java. * In WebLogic, this is implemented by the code-generated container * class ChefBeanC. A home interface may support one or more create * methods, which must correspond to methods named "ejbCreate" in the EJBean. * */ public interface ChefHome extends EJBHome { /** * Corresponding to the ejbCreate method in the ChefBean.java. * * @return ChefInterface * @exception RemoteException * @exception CreateException */ ChefInterface create() throws CreateException, RemoteException; } The ChefHome interface enables the WaiterBean class to obtain a handle to the ChefBean stateless session bean. In this scenario the WaiterBean stateful session bean acts as an EJB client to the ChefBean stateless session bean. The create() method defined in the ChefHome interface returns an object of type ChefInterface, which is the remote (or local) object reference. The ChefHome interface extends the javax.ejb.EJBHome interface. The create() method throws the exceptions javax.ejb.CreateException and java.rmi.RemoteException (for remote interfaces only) when an error occurs while creating the ChefInterface remote object. The final class that you will be studying is the ChefBean class, shown in Listing 11.3. Listing 11.3 ChefBean.java
/****************************************************************************** * Class Name : ChefBean.java * Description : Bean Class for the ChefBean bean. * Implements the methods defined in the Home and Remote * interfaces. These methods are called by the Waiter bean. * @author Mandar S. Chitnis, Lakshmi AM, Pravin S. Tiwari. @version 1.1 * Copyright (c) by Sams Publishing. All Rights Reserved. ******************************************************************************/ package com.sams.learnweblogic7.ejb.stateless; import javax.ejb.CreateException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import javax.naming.InitialContext; import javax.naming.NamingException; public class ChefBean implements SessionBean { private String chefId; private static final boolean ENABLE_WEBLOGIC_LOGGING = true; private boolean isAvailable; private SessionContext ctx; /** * As per EJB Specifications to be implemented by bean, * Used when create is called on the remote interface */ public void ejbCreate(){ webLogicLog("Method ejbCreate has been called"); } // Using WebLogic's log service to log events private void webLogicLog(String logMessage) { if (ENABLE_WEBLOGIC_LOGGING) System.out.println(logMessage); } //end of webLogicLog /** * As per EJB Specifications to be implemented by bean, * Presently not being used */ public void ejbRemove() { webLogicLog("Method ejbRemove has been called"); }//end of ejbRemove /** * Sets the session context. * * @param ctx SessionContext Context for session */ public void setSessionContext(SessionContext ctx) { webLogicLog("Method setSessionContext has been called"); this.ctx = ctx; }//end of setSessionContext /** * This method is called by the waiter to cook the item. * * @param orderedItem MenuItem object ordered item * @return object CookedItem */ public CookedItemImpl cookItem(MenuItem orderedItem){ webLogicLog("cook Item called"); System.out.println("Menuitem is "+orderedItem.getItemDesc()); CookedItemImpl preparedItem = new CookedItemImpl(); System.out.println ("The cooked Item is:"+orderedItem.getItemDesc()); if((orderedItem.getItemDesc()).equals("Apple Pie")){ preparedItem.setItemName("Apple Pie"); preparedItem.setServingSize("Standard"); preparedItem.setTaste("Sweet"); preparedItem.setIngredients ("Apple, Sugar, All Purpose Flour, Eggs, Butter"); preparedItem.setTemperature("Hot"); } else if((orderedItem.getItemDesc()). equals("Banana Split Icecream")){ preparedItem.setItemName("Banana Split Icecream"); preparedItem.setServingSize("One Scoop"); preparedItem.setTaste("Sweet"); preparedItem.setIngredients ("Milk, Sugar, All purpose flour, Eggs, Cream, Bananas"); preparedItem.setTemperature("Cold"); } else if((orderedItem.getItemDesc()).equals("Cheese Pizza")){ preparedItem.setItemName("Cheese Pizza"); preparedItem.setServingSize("Standard"); preparedItem.setTaste("Salty"); preparedItem.setIngredients("All purpose flour, Cheese, Jalapenos, Tomatoes, Bell Peppers, Olives, Salt"); preparedItem.setTemperature("Hot"); } else if((orderedItem.getItemDesc()).equals("Curly Fries")){ preparedItem.setItemName("Curly Fries"); preparedItem.setServingSize("Standard"); preparedItem.setTaste("Salty"); preparedItem.setIngredients("Low cholesterol oil, Potatoes cut, Salt"); preparedItem.setTemperature("Hot"); } else if((orderedItem.getItemDesc()).equals("Delhi Kababs")){ preparedItem.setItemName("Delhi Kababs"); preparedItem.setServingSize("10 pieces"); preparedItem.setTaste("Spicy"); preparedItem.setIngredients("Onions, Coriander powder, Poppy seeds, Ginger, Salad Oil, Salt, Garlic, Spices, Red Chillies, Chicken, Yogurt"); preparedItem.setTemperature("Hot"); } else if((orderedItem.getItemDesc()). equals("Fresh Pineapple Cake")){ preparedItem.setItemName("Fresh Pineapple Cake"); preparedItem.setServingSize("1 Slice"); preparedItem.setTaste("Sweet"); preparedItem.setIngredients ("Pineapple, Sugar, All purpose flour, Eggs, Butter"); preparedItem.setTemperature("Room Temperature"); } else if((orderedItem.getItemDesc()).equals("French Fries - Tub")){ preparedItem.setItemName("French Fries - Tub"); preparedItem.setServingSize("Large"); preparedItem.setTaste("Salty"); preparedItem.setIngredients ("Low cholesterol oil, Potatoes cut, Salt"); preparedItem.setTemperature("Hot"); } else if((orderedItem.getItemDesc()).equals("Hot Dog")){ preparedItem.setItemName("Hot Dog"); preparedItem.setServingSize("Standard"); preparedItem.setTaste("Salt"); preparedItem.setIngredients ("Hot Dog buns, Meat, Bread crumbs, Oatmeal flour, Oatmeal flour, Little egg white, Spices - Onion, Garlic, Salt, Pepper etc"); preparedItem.setTemperature("Hot"); } else if((orderedItem.getItemDesc()).equals("Hamburger")){ preparedItem.setItemName("Hamburger"); preparedItem.setServingSize("Standard"); preparedItem.setTaste("Salty"); preparedItem.setIngredients ("Hamburger, Lettuce, Onions, Tabasco sauce, Cheddar Tabasco sauce, Cheddar cheese, Kaiser style buns, Pam cooking spray, Worcestershire sauce"); preparedItem.setTemperature("Hot"); } return preparedItem; }//end of cookItem } The primary functionality of the chef is written in the ChefBean bean class. As a part of the EJB component design contract, the ChefBean implements the life-cycle callback methods of a stateless session bean, such as setSessionContext(), ejbCreate(), and ejbRemove(). These callback methods will be invoked by the EJB container at different stages of the stateless session bean's life cycle. In addition, the ChefBean class provides the implementation of the cookItem() method defined in the bean's remote interface. The functionality in the cookItem() method is exactly the same as was described yesterday. Finally, you need to make one change in the WaiterBean stateful session bean to change the way you instantiated the ChefInterface object. Now that you have rewritten the chef functionality as a bean, the WaiterBean stateful session bean acts as an EJB client for the ChefBean bean. You only need to modify the getChefFromChefPool() method in the WaiterBean class. In the getChefFromPool() method of the WaiterBean class in yesterday's code, the instance of the ChefInterface object was obtained from PoolClass class using the getChef() method. Because the pool-handling functionality is now handled by the EJB container, you will not require the PoolClass class. Here is the code snippet for changes to the getChefFromChefPool() method of the WaiterBean bean class: //called by the waiter to get a chef from the chef pool public ChefInterface getChefFromChefPool(){ ChefInterface chef=null; try{ ChefHome chefHome = lookupHome(); chef = (ChefInterface)PortableRemoteObject. narrow(chefHome.create(), ChefInterface.class); } catch(Exception e){ e.printStackTrace(); } return chef; } /** * Lookup the EJBs home in the JNDI tree */ private ChefHome lookupHome() throws NamingException { // Lookup the beans home using JNDI //(Properties can be used instead of Hashtable, //to keep the code compatible with jdk1.1 also.) try{ Hashtable h = new Hashtable(); h.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); h.put(Context.PROVIDER_URL, "t3://localhost:7001"); Context ctx = new InitialContext(h); System.out.println ("Initial context to look up chef home created"+ctx); String ctxName = ctx.getNameInNamespace(); NamingEnumeration myNamingEnum = ctx.list(ctxName); while(myNamingEnum.hasMoreElements()){ System.out.println ("Naming Enum : "+myNamingEnum.nextElement()); } Object home = ctx.lookup(CHEFHOME_JNDI_NAME); System.out.println("Lookup performed"); return (ChefHome)PortableRemoteObject.narrow(home, ChefHome.class); } catch (NamingException namingException) { System.out.println("Unable to lookup EJBHome ChefHome."); System.out.println ("Check JNDI name "+CHEFHOME_JNDI_NAME+" on the WebLogic server"); throw namingException; } } The first statement in the method is to invoke the lookupHome() method. The lookupHome() method creates a new InitialContext() object and sets the properties to look up the ChefHome object using the lookup() method on the InitialContext. The call to the lookup() method retrieves the ChefHome home interface of the ChefBean stateless session bean. This ChefHome object is typecast to the appropriate type using the narrow() method and returned to the getChefFromPool() method. The create() method is now called on the ChefHome object to obtain the reference to the chef bean's remote interface. Notice how a clean and simple design went a long way in minimizing changes to the chef and the waiter classes and converting the chef classes to a stateless session bean. Compile the Program
Compiling the files of the restaurant application is a two-step process. Use the provided compile.bat batch file to compile the classes and interfaces of the restaurant application. This includes the WaiterBean stateful session bean classes, the Customer EJB client, and the supporting Java classes. The batch file compiles the files of the restaurant application located in the directory C:\book\code\EJB\stateless\src\*.java The command used for compiling is javac -d C:\book\code\EJB\stateless\deploy C:\book\code\EJB\stateless\src\*.java After generating the .class files for the source code, the next step is to edit the deployment descriptor files ejb-jar.xml and the WebLogic-specific deployment descriptor file weblogic-ejb-jar.xml to register the stateless session bean with the WebLogic Server; see Figure 11.4. Figure 11.4. The ejb-jar.xml deployment descriptor file.Because you are already familiar with the different tags used to register a session bean, this lesson will only talk about the tags used to register the ChefBean stateless session bean. After registering the session bean in the ejb-jar.xml file, you need to register the WebLogic specific deployment information in the weblogic-ejb-jar.xml file; see Figure 11.5. Figure 11.5. The weblogic-ejb-jar.xml deployment descriptor file.The registration information of the chef EJB is defined within these tags. Within the <weblogic-enterprise-bean></weblogic-enterprise-bean> tags, you should register the JNDI name for an EJB. To do this you must use the <jndi-name></jndi-name> tags for the JNDI name of the EJB listed in the <ejb-name></ejb-name> tags. After compiling the .class files and registering the bean in the ejb-jar.xml and weblogic-ejb-jar.xml deployment descriptor files, you need to group the .class files and the deployment descriptor files into a Java archive file. To do this, you first need to copy the deployment descriptor files to a directory named META-INF and then generate the java archive using the command: jar cvf stateless.jar META-INF/ com\sams\learnweblogic7\ejb\stateless\*.class From Figure 11.6 you can see that the jar command creates a Java archive named stateless.jar containing the deployment descriptor files in the META-INF directory and the .class files of the restaurant application; see Figure 11.6. Figure 11.6. The creation of the stateless.jar Java archive file.The next step is to compile the stateless.jar Java archive using the weblogic.ejbc compiler of WebLogic Server. To do so, use this command: java weblogic.ejbc stateless.jar EJBStatelessDeploy.jar The ejbc compiler combines together the EJB classes, interfaces, and deployment descriptor files and generates a Java archive file EJBStatelessDeploy.jar. In addition, the ejbc compiler generates the client-side stub classes, server-side skeleton classes, and EJB container implementation classes (for EJBHome and EJBObject/EJBLocalObject) after validating the bean classes and interfaces written by the bean provider. Now the ChefBean stateless session bean is ready to be deployed in the EJB container of the WebLogic Server. Deploy the Program
The steps for deploying the stateless session bean are exactly the same as the steps that you performed yesterday for a stateful session bean. You can use any of the three different ways you learned yesterday to deploy the ChefBean stateless session bean. Execute the Program
After deploying the ChefBean bean, start up WebLogic Server and then start the Customer EJB client at another command prompt. After executing the Customer class, you can observe the output shown in Figure 11.7 in the command-prompt window. Figure 11.7. The output in the command-prompt window of the Customer class.As the Customer class progresses through its actions and interacts with the WaiterBean stateful session bean, and as the WaiterBean interacts with the ChefBean stateless session bean, the output shown in Figure 11.8 will be displayed on the console of the WebLogic Server. Figure 11.8. The output of the ChefBean in the command-prompt window of the WebLogic Server console. |