Advanced Internet Programming - EJB 31242/32549/ AJPCPEAdvanced Internet Programming INFO: What's New FAQ Software Machines Oracle Assignments MODULES: 00 Admin 01 Intro 02 Architecture 03 Servlets 04 JSP 05 JDBC 06 RMI 06 JNDI 07 EJB 08 XML 08 Web Services 09 Security 10 Transactions 11 Legacy 12 Review 99 Design LINKS: START page Faculty of IT UTS Module: EJB Tutorial exercise - creating a Stateless Session Bean manually In this lab exercise, we create your first Enterprise JavaBean. It will be a stateless session bean. Level of Difficulty: 2 (moderately easy) Estimated time: 60 minutes Pre-requisites: Run wlenv to set your environment correctly Start your WebLogic server running in the background Overview of EJB Enterprise JavaBeans implement the business logic of a J2EE application. Each EJB, or "bean", is a component, i.e. it is treated as a single, logical entity that presents a public interface defining its methods that can be accessed. EJBs are deployed into an application server (in this context, also known as an "EJB container"). In our case, this is WebLogic. Note that WebLogic contains both a web server (for servlets/JSPs) and an application server (for EJBs). Logically they are separate, even though they are implemented in the same product. An application server contains a collection of EJBs. The application server provides a lot of support for the EJBs that it hosts. There are different kinds of EJBs. These are discussed in more detail in the lecture, but for now suffice to say that in this exercise we will be creating an EJB Session Bean. A session bean is a transient kind of EJB that is created when a client requests it, and is destroyed when the client is finished (i.e. it lasts for one "session"). To be more specific, we will be creating a Stateless Session Bean, which means that during a single session with a client, the bean does not maintain any internal state information. The basic model of a stateless session bean is that it is a component with a set of public business-logic methods, and the methods are all independent of each other. One method should not rely upon any other method having previously been called. In this example, the client of our EJB will be a servlet (the presentation tier calling methods on the business-logic tier). Development Process Just as there were many steps in developing an RMI application, there are also many steps in developing and deploying an EJB. It is important to follow the correct sequence of steps, as outlined below. Create the Remote interface. The "Remote interface" is where you decide what kind of service(s) your EJB is going to offer to its clients. The remote interface is a Java interface that defines a set of method signatures that the EJB will implement, and that the clients can call. The remote interface defines your business logic methods. The remote interface is shared by both clients and the EJB implementation. Create the Home interface. We have already seen the Remote interface which contains business logic methods. The "Home interface" of an EJB session bean contains methods for creating a new instance of the bean. Clients first obtain a reference to a bean's home interface, and from the home interface, can create one or more instances of the bean itself. Create the EJB implementation class. Naturally you need to create a Java class which provides the implementation of your business-logic methods (and some others, as we will see). Write the EJB deployment descriptor. Recall how web applications (in a WAR file) required an XML deployment descriptor? EJBs also require a deployment descriptor, that provides instructions to the EJB container as to how the EJB should be deployed. Package the EJB into a JAR file. Web applications are packaged in WAR files. EJBs are packaged in JAR files. They are basically the same concept. Generate stubs and skeletons. Next we use an "EJB compiler" tool that will take the JAR file created in the previous step, and will generate stubs and skeletons for the EJB, and will also compile all the Java source code. The EJB compiler will also check the syntax of your XML deployment descriptor. This is quite similar to running "rmic" (the RMI compiler) to generate stubs and skeletons when creating pure RMI applications, except now it is a different tool. Deploy the EJB into an application server. The JAR file containing your EJB must be deployed before it can be invoked, in the same way as WAR files must be deployed before your servlets/JSPs can be invoked. Create an EJB client - a servlet. You cannot directly run your EJB and see results immediately. First you need to create a client program that will invoke the business-logic methods on the EJB, and display some results. In this exercise, we will create a servlet as our EJB client, but note that the client could be a servlet, a JSP, a standalone Java application, or even another EJB. Copy EJB stubs + home/remote interface classes to the WEB-INF/classes directory of your WAR file. Recall that in RMI, the client needed access to the Java classes for the interface and the stubs. The same is true for EJB - an EJB client must have access to these classes. In the case of a servlet client, that means we need to copy some of the EJB's class files into the servlet's WAR file. Create the WAR file and deploy. This step is just the normal process of packaging and deploying a Java servlet. Creating an EJB stateless session bean Step 0 (Optional)- Using Eclipse/Workshop You can use Eclipse to create the following files. To do so, create a new EJB Project. Create a new -> project -> , select Show All Wizards, type in EJB in the filter text & select EJB Project Change the configuration from Weblogic EJB Project Facets to Custom & enter a project name When in the Project Facets wizard, ensure Weblogic EJB Extension is not selected. Step 1 - Create the Remote interface The Remote interface is a Java interface declaration, containing a list of methods (signature only) that you want your clients to be able to invoke. Create and compile the following Java source file. package myapp;
import java.rmi.*;
import javax.ejb.*;
public interface HelloWorld extends EJBObject {
public String hello(String name) throws RemoteException;
}
Points to notice: Clients will only be able to invoke one method on the server - the method is called hello(), and it takes 1 string argument and returns a String. The interface extends EJBObject (javax.ejb.EJBObject). All EJB remote interfaces must do this. The method declares that it may throw a RemoteException. All methods in a remote interface must declare this. A RemoteException may be thrown by the underlying infrastructure if anything goes wrong with the communication between the client and server. This is the same as for RMI. Although it is not clearly shown here, both the parameters and the return type of remote methods must be Java classes that implement the java.io.Serializable interface. Step 2 - Create the Home interface The Home interface is also a Java interface declaration, containing a list of methods (signature only) that your clients can invoke. However the home interface has a special function. Before clients can access the business-logic methods of your EJB (i.e. the ones defined on the Remote interface), they must first obtain a Home interface, and from the Home interface, create an instance of the EJB. Every EJB must have both a Home and a Remote interface. Create and compile the following Java source file. package myapp;
import java.rmi.*;
import javax.ejb.*;
public interface HelloWorldHome extends EJBHome {
public HelloWorld create ()
throws RemoteException, CreateException;
}
Points to notice: To create an instance of the EJB, clients will call a method named create() that takes no arguments, and returns an object whose type is that of the Remote interface. You could define more than one create method if you wish, as long as each one you define takes a different set of arguments. The interface extends EJBHome (javax.ejb.EJBHome). All EJB home interfaces must do this. The method declares that it may throw a RemoteException and/or a CreateException. All "create" methods in a home interface must declare this. Either of these exceptions may be thrown by the underlying infrastructure if anything goes wrong during the creating of the EJB. Step 3 - Create the EJB implementation class This is the class that actually implements the EJB methods. It must provide public method implementations for all methods defined in the Remote interface. It must also implement all the create methods defined on the Home interface (except they are renamed slightly to ejbCreate()). The EJB implementation class may define other methods, but only the ones listed in the remote interface can be invoked over the network by clients. Create and compile the following Java source file. If using Eclipse, you don't need to compile as this is done automatically. package myapp;
import javax.ejb.*;
public class HelloWorldBean
implements SessionBean {
SessionContext sessionContext;
// SessionBean methods
public void setSessionContext (SessionContext sc) {
this.sessionContext = sc;
}
// Argument list must match create() method
// in HelloWorldHome interface
public void ejbCreate() { }
public void ejbRemove() { }
public void ejbActivate() { }
public void ejbPassivate() { }
// Now our business logic methods
public String hello(String name) {
return ("Hello, " + name);
}
}
Points to notice: The class implements SessionBean (javax.ejb.SessionBean). All EJB session beans must do this. Notice though that this class does not implement the Remote interface we defined earlier. This is different to an RMI implementation class. The methods in the bean can be divided into two kinds: standard session bean methods these include setSessionContext(), plus all the methods whose names start with ejb (ejbCreate(), ejbRemove(), ejbActivate(), ejbPassivate()). These methods are defined by the javax.ejb.SessionBean interface. business logic methods these are the methods you you defined in your Remote interface. In this example there is only one. The EJB container (e.g. application server, i.e. WebLogic) will pass to us a SessionContext object. We store that object in case we later want to access some facilities of the EJB container itself. Step 4 - Write the EJB deployment descriptor Just like packaged web applications (WAR files) needed a deployment descriptor, so too do packaged EJBs. In fact, EJBs will need two deployment descriptors. One is a J2EE standard deployment descriptor that will be the same regardless of which application server you use (WebLogic, WebSphere, JBoss, etc). This one goes in a file called ejb-jar.xml. The other is a container-specific deployment descriptor - its syntax will be different depending on which product you use to deploy your EJB. This one goes in a file called weblogic-ejb-jar.xml. EJB deployment descriptors are placed into a subdirectory called META-INF. Note that this is different to the directory name you used for WAR files (which was WEB-INF). Create the following file as ejb-jar.xml in a subdirectory called META-INF.
HelloWorld
myapp.HelloWorldHome
myapp.HelloWorld
myapp.HelloWorldBean
Stateless
Container
HelloWorld
Remote
*
Required
Secondly, create the following file as weblogic-ejb-jar.xml in the same META-INF directory as your other deployment descriptor.
HelloWorld
100
ejb/HelloWorld
Step 5 - Package the EJB into a JAR file EJBs are packaged in JAR files, which are created using the jar command. The syntax is exactly the same as when you created WAR files. If running Eclipse, you can do the following steps by using the Right Mouse Button -> Export -> EJB Jar file option. Before creating the JAR file, check that the files are in the correct directories. There is one directory for the Java package that the classes are in, and the other directory is META-INF. /myapp
- HelloWorld.class
- HelloWorld.java
- HelloWorldHome.class
- HelloWorldHome.java
- HelloWorldBean.class
- HelloWorldBean.java
/ META-INF
- ejb-jar.xml
- weblogic-ejb-jar.xml
Run the jar command from this directory as follows: jar cf ../HelloEJB.jar *
Step 6 - Generate stubs and skeletons With RMI, you have to run a tool that generates stubs and skeletons for the RMI application. For EJB you also have to run a tool that generates stubs and skeletons, however it is a different tool. WebLogic uses a tool called appc. This tool takes either a JAR or EAR file as input. The syntax is as follows. cd ..
java weblogic.appc HelloEJB.jar
If you have errors in your JAR file (for example, incorrect directory structure, invalid syntax in the deployment descriptor), appc will usually alert you. Step 7 - Deploy the EJB into an application server The process of deploying an EJB is identical to deploying a web application. You just copy the JAR file into the "applications" subdirectory of your WebLogic installation. cp HelloEJB.jar ~/weblogic/autodeploy
Watch the WebLogic server window to see if there were any errors during deployment. If the EJB was deployed successfully, you will find its name will appear in the JNDI tree of your WebLogic server. Open a management console, and go to "Servers", "myserver", then move to the "Monitoring" tab and choose "View JNDI tree". Your EJB name should appear with a purple dot next to it. This indicates that your EJB is advertising itself in the name service as being available to clients. Step 8 - Copy EJB stubs + home/remote interface classes to the WEB-INF/classes directory of your WAR file Just as with RMI, the "client" (in this case a servlet) needs access to the stub files generated by ejbc. Because the client is packaged separately from the EJB, the stubs need to be manually copied from the ejbc-generated output into the servlet's WAR file. Change directory into the WEB-INF/classes directory of your WAR file, and run the following JAR command that will extract the contents of the EJB JAR file into the WEB-INF/classes directory. This will make sure the compiled stubs and compiled home/remote interfaces are available to the client. Note that it will also make other, unnecessary, classes available to the client, but we ignore those now for simplicity. cd WEB-INF/classes
jar xvf /mypath/HelloEJB.jar
You will need to change /mypath/ to represent the directory path of where you have placed your EJB JAR file. ! ALTERNATIVELY could just just copy the entire jar file into the WEB-INF/lib directory Step 9 - Create an EJB client - a servlet Here we will use a Java servlet as the client to our EJB. You should create your WAR file directory structure in a different place to where you created the JAR file for your EJB. The WAR file and the JAR file are completely independent. Create and compile the following Java source file. import myapp.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import java.util.*;
public class HelloWorldServlet extends HttpServlet {
public void doGet (HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/plain");
PrintWriter out = res.getWriter();
out.println("----------------------------------------");
try {
Context ctx = new InitialContext();
out.println("Got context");
HelloWorldHome hwsh;
Object ref = ctx.lookup("ejb/HelloWorld");
hwsh = (HelloWorldHome) PortableRemoteObject.narrow(
ref, HelloWorldHome.class);
out.println("Got home interface");
HelloWorld hws = hwsh.create();
out.println("Created EJB");
out.println(hws.hello("chris"));
}
catch (Exception e) {
e.printStackTrace(out);
}
out.println("----------------------------------------");
}
}
Remember that the compiled servlet class must go in the WEB-INF/classes subdirectory. Also note that the servlet will not compile unless you have the directory "." (which means the current directory) in your CLASSPATH. The WebLogic setEnv.sh script does not automatically put "." in your CLASSPATH, so you may have to add it manually if you have not already. In a text editor, open the file ~/weblogic/bin/setDomainEnv.sh, and search for the line that starts "CLASSPATH=...". In this line, add "." to the list of directories. You could also equally place the EJB lookup & execution code (basically the entire try-catch block!) into a scriptlet in a JSP. This way you do not have to compile the servlet. Regarding the servlet code itself, notice the sequence of operations for the client: Create an InitialContext so we can look up a name service, to find the EJB. No parameters are supplied when we create the InitialContext so we will use the name service supplied by the container (WebLogic), which is what we want in this case. Look up the "JNDI name" of the EJB. Recall that when you created the EJB, you specified its JNDI name in the weblogic-ejb-jar.xml deployment descriptor. That is the name that we use here to perform the lookup. If the lookup is successful, we will be returned with a Java object of type HelloWorldHome - i.e. the EJB's Home interface. Now that we have a reference to the Home interface, we can call the create() method which will give us a reference to the EJB itself (i.e. its Remote interface). Finally, now that we have a reference to the EJB's Remote interface, we can call business logic methods of the EJB as defined on the Remote interface (in this case the method hello()). This may seem a slightly strange process. Just remember that first we obtain a reference to the EJB's Home interface, and from that we create an instance of the EJB which returns an instance of the EJB's Remote interface. Step 10 - Create the WAR file and deploy Now that you have created your servlet, and copied the stubs and interfaces so they are accessible to the servlet, you can create the WAR file for the servlet, and deploy it to WebLogic. The process is the same as you have used for creating and deploying WAR files in the past. Note that you will need to create a web.xml file in the WEB-INF directory for the servlet. There is nothing special about this web.xml file - it will be the same as you have created before. To deploy your WAR file, copy it to the "autodeploy" subdirectory of your WebLogic installation. Running the HelloWorld EJB example To test your application, open a web browser window, and enter the URL of your servlet into the Location field. If all goes well, your servlet will execute, and will make a remote method call to the EJB that is executing in the application server. Next step ... Now that you have followed a step-by-step walkthrough, the next step is to be a bit more independent. Modify the example above to include a new remote method that will add together two integers (i.e. it takes two integer arguments, and returns an integer result). This will involve changing the remote interface, and then re-running all the subsequent steps. © 2008 University of Technology, Sydney. All Rights Reserved. Redistribution without permission prohibited.