Docstoc

Enterprise Java Beans

Document Sample
Enterprise Java Beans Powered By Docstoc
					1

Enterprise Java Beans
Enterprise Java Beans (EJBs) are Java’s equivalent of COM+ components. Just like DCOM is a layer on top of DCE-RPC using proxy-stub dlls for marshalling of parameters and returned values from method calls, similarly, EJBs use RMI underneath and require skeleton-stubs for communication between the client and the remote component. Here is how the Microsoft COM and Java technologies appear in terms of their layers. DCOM – COM+

EJB

DCE-RPC

RMI

Sockets

Sockets

Let us briefly review how sockets can be used to achieve a remote method invocation, then we will simplify it by using RMI, and finally discuss the EJB architecture for developing scalable, transactional components.

Using Simple Sockets to Achieve Remote Method Calls:
RMI and EJBs allow calling remote methods in an easy straightforward manner. However, both use sockets underneath as the primary communication mechanism. To give you a better idea of this, we will develop a simple server and a client in which the client will communicate to the server via socket. The socket communication code will be wrapped in two special classes called the Stub and the Skeleton (this is equivalent to the proxy-stub code in DCOM).

Client

Server

Stub Object

Skeleton Object

Network - Socket

2 The client will use the Stub object to make method calls. The Stub object will pass the method names (and parameters if needed) by making a socket connection to the Skeleton server. The Skeleton server (which is a TCP server) will read the method names (and parameters) from the socket, call the corresponding method in the server, receive the returned values and put them back on the socket.

Example: Let us develop a Student class which will act as a server. We may create an
interface for this class as (Create a directory called socketrmi, then type the following in a file called StudentIntf.java): // ----StudentIntf.java ---public interface StudentIntf { public int getStudentID() throws Throwable; public String getName() throws Throwable; } Create another file called “StudentServer.java” (in the socketrmi directory) that will implement the above interface. //---StudentServer.java --public class StudentServer implements StudentIntf { int ID; String name; public StudentServer(int ID, String name) { this.ID = ID; this.name = name; } public int getStudentID() { return ID; } public String getName() { return name; } } We will create two special files called Student_Stub (to be used on the client side) and Student_Skeleton (used on the server side). These two will set up the primary socket communication mechanism and will stream the method names and the returned values over the socket. //---Student_Stub.java --// showing the effect of a stub code with sockets

3 import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.net.Socket; public class Student_Stub implements StudentIntf { Socket sock; public Student_Stub() throws Throwable { sock = new Socket("localhost",8888); // you can try a different host as well // 8888 is the port number } public int getStudentID() throws Throwable { // stream the method name to skeleton ObjectOutputStream ostm = new ObjectOutputStream(sock.getOutputStream()); ostm.writeObject("getStudentID"); ostm.flush(); ObjectInputStream istm = new ObjectInputStream(sock.getInputStream()); return istm.readInt(); } public String getName() throws Throwable { // stream the method name to skeleton ObjectOutputStream ostm = new ObjectOutputStream(sock.getOutputStream()); ostm.writeObject("getName"); ostm.flush(); ObjectInputStream istm = new ObjectInputStream(sock.getInputStream()); return (String) istm.readObject(); } } //---Student_Skeleton.java --// showing the effect of a skeleton code with sockets // Skeleton is on the server side, so it will need to create // a TCP server socket and wait for client (Stub) to connect import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.net.Socket; import java.net.ServerSocket;

4 public class Student_Skeleton extends Thread { StudentServer myServer; public Student_Skeleton(StudentServer server) { this.myServer = server; // now we have reference to } // a StudentServer object public void run() { try { ServerSocket serversock = new ServerSocket(8888); // server socket listening on port 8888 Socket sock = serversock.accept(); // wait for incoming connection from a client while (sock != null) { ObjectOutputStream ostm = new ObjectOutputStream(sock.getOutputStream()); ObjectInputStream istm = new ObjectInputStream(sock.getInputStream()); String methodname = (String) istm.readObject(); if (methodname.equals("getStudentID")) { int ID = myServer.getStudentID(); ostm.writeInt(ID); ostm.flush(); } else if (methodname.equals("getName")) { String nm = myServer.getName(); ostm.writeObject(nm); ostm.flush(); } } } catch(Throwable t) { t.printStackTrace(); System.exit(0); } } public static void main(String args[]) { // stream the method name to skeleton StudentServer st = new StudentServer(5837,"Ausif Mahmood"); Student_Skeleton sk = new Student_Skeleton(st); sk.start(); // run the thread } } Now we need to create a client. Type the following in a file called “StudentClient.java” also in the socketrmi directory.

5 //--- StudentClient.java--public class StudentClient { public static void main(String args[]) { try { // client will use the stub to talk to a server StudentIntf iSt = new Student_Stub(); int ID = iSt.getStudentID(); String nm = iSt.getName(); System.out.println(" ID = " + ID + "Name = " + nm); } catch(Throwable t) { t.printStackTrace(); } } } Compile all the above five files. From the DOS prompt, move to socketrmi directory, then type the following commands. javac –classpath “.” StudentIntf.java javac –classpath “.” StudentServer.java javac –classpath “.” Student_Stub.java javac –classpath “.” Student_Skeleton.java javac –classpath “.” StudentClient.java Now run the server first by typing the following command: java Student_Skeleton Then from another DOS window, move to the socketrmi folder, then type: java StudentClient You will see the following output:

Remote Method Invocation (RMI): RMI allows a Java client to invoke
methods of a remote object of a Java class. It automates quite a few of the things that needed to done manually when using plain sockets for method calls. For example, it provides an rmi compiler that will generate the stub and skeleton class files, so you do not have to write any socket code. It provides an rmi registry where the servers can register themselves and the clients can lookup and obtain a reference to a remote server. Just like RPC is built on top of sockets, so is RMI.

6 In DCOM, the interaction with the proxy-stub dll is hidden in the sense that client calls to the remote methods appear as if the COM server is local. However, in Java, you need to create a “remote interface” which will be provided to the client. The client will make calls to the methods in the remote interface (don’t get confused by the term remote as this interface also resides in the same machine as the client). The client makes calls to the remote interface which then uses the stub-skeleton to communicate to the remote server. Just like DCOM (midl), a special compiler (rmic) will be used to create the stubskeleton code. Rules for remote interfaces: All remote interfaces must extend the Remote interface which is defined in java.rmi. Remote interface has no members and its purpose is to simply indicate that the interface contains remote methods. The remote methods can throw a RemoteException. Example: Create a directory called rmiex where you will be typing some files. Using a text editor, prepare a file called AvgServerIntf.java in the rmiex folder with the following code in it. // ---AvgServerIntf.java // ---Remote Interface for AvgServer--import java.rmi.*; public interface AvgServerIntf extends Remote { double computeAvg(int a1, int a2) throws RemoteException; } Create another file called AvgServerImpl.java in the rmiex folder with the following code. All remote objects must extend the UnicastRemoteObject which provides the functionality to make objects available from remote machines. // --- AvgServerImpl.java --import java.rmi.*; import java.rmi.server.*; public class AvgServerImpl extends UnicastRemoteObject implements AvgServerIntf { public AvgServerImpl() throws RemoteException { } public double computeAvg(int a1, int a2) throws RemoteException { return (a1+a2)/2.0f ; } } Create another file called RegisterAvgServer.java in the rmiex folder with the following code. Its main purpose is to register the AvgServer with the RMI registery (think of this as equivalent to the dllRegisterServer code in a COM server). // ---RegisterAvgServer.java----

7 import java.net.*; import java.rmi.*; public class RegisterAvgServer { public static void main(String ars[]) { try { AvgServerImpl avgserver = new AvgServerImpl(); Naming.rebind("AvgServer",avgserver); // AvgServer is the name that the naming service // will honor. Think of it as the CLSID equivalent } catch(Exception e) { System.out.println("Problem in Registration: " + e); } } }

Create a file to be solely used on the client side called AvgClient.java. It will use the Naming service to lookup a reference to the server. //---AvgClient.java---import java.rmi.*; public class AvgClient { public static void main(String args[]) { try { // first parameter is IP address of server String avgServerURL = "rmi://" + args[0] + "/AvgServer"; AvgServerIntf avf = (AvgServerIntf)Naming.lookup(avgServerURL); int a, b; a = 23; b = 38; double c = avf.computeAvg(a,b); System.out.println("Avg of " + a + ", " + b + " = " + c); } catch (Exception e) { System.out.println("Error occured : " + e); } } } First compile the four files developd above by using the javac compiler i.e., from the DOS prompt, you can type. You will need to set the class path properly. For example, I had created the rmiex folder inside the MyJava directory, so from the DOS prompt cd to the c:\MyJava\rmiex folder, then type: javac –classpath “c:\MyJava\rmiex\” AvgServerIntf.java

8 javac –classpath “c:\MyJava\rmiex\” AvgServerImpl.java javac –classpath “c:\MyJava\rmiex\” RegisterAvgServer.java javac –classpath “c:\MyJava\rmiex\” AvgClient.java Now we need to generate the stub and skeleton code. Note that in Java 1.2 and later, the skeleton is not required. From the DOS prompt, once you are in the rmiex folder type the following command: rmic –classpath “.” AvgServerImpl This will create two class files called: AvgServerImpl_Skel.class and AvgServerImpl_Stub.class. Now copy the AvgServerImpl_Stub.class, AvgServerImpl_Skel.class, AvgServerIntf.class, AvgServerImpl.class and RegisterAvgServer.class files to a remote server. In my case it is a different machine having an IP address of 192.107.40.140. On the remote server machine, type the following from the DOS prompt. start rmiregistry Then register the server by typing. java RegisterAvgServer On the client machine, invoke the AvgClient program as shown below.

The downside of RMI is that the servers run inside a JVM. This could become very expensive if many server objects need to be created to serve concurrent clients. To solve this problem, the EJB architecture was devised. Many of the ideas in the EJB design have been borrowed from MTS and COM+. So in some ways, if you understand COM+, EJB is straightforward. Just like COM+ (and MTS), EJB provides an application server whose job is to invoke components, provide object pooling, persistence, transactions and a security mechanism. The development of an EJB component follows a few well defined steps. The tricky part of an EJB component is its deployment in an application server. Since different vendors have different mechanisms for EJB deployment, you need to completely follow the deployment instructions for a particular EJB application server that you are using. Let us first take a look at the main categories of EJB components and then we will go through an example to develop and deploy an EJB component.

9

EJB Component Services and Categories:
EJB is one of the standards for building software components for enterprise information systems. The EJB specification makes use of numerous standard Java API's to provide a rich set of services to developers. There are two main kinds of EJB components called entity beans and session beans.

Persistence Service-Entity Beans:
Many business systems today use a relational database to store data when it is not in main memory. Entity Beans provide some help in manipulating persistent data. An example of an entity bean might be a customer, order, student, patient etc..A developer can specify an entity bean as using container managed persistence (CMP) or bean managed persistence (BMP). For CMP, the EJB container is responsible for saving/loading the state of the component i.e., the container implements the database operations (normally referring to a mapping of attributes to table columns supplied in XML files called deployment descriptors that are packaged with an EJB). Think of a container as a virtual server running inside the EJB application server. Bean managed persistence (BMP) requires the bean's developer to implement the database operations (normally using Java's JDBC API). CMP is usually restricted to mapping a bean’s attributes to columns in a single database table. i.e. each entity bean represents one row in that table thus avoiding many of the OO to RDBMS mapping issues. Anything more sophisticated often requires switching to bean managed persistence or using session beans altogether. Both for CMP and BMP, EJB provides database connection pooling so you do not have to worry about pooling database connections yourself. EJB also provides object pooling for memory-less session beans. Object pooling does not make sense for entity beans since entity beans require a single client. For example a client may want to create a student entity bean to create a new student (or acquire an existing student), then the client may use the Notice that COM+ provide only equivalent of session beans and have no counter part to entity beans. It is a debatable issue whether entity beans make your life easier or are counter productive. Supposedly Microsoft pursued an idea similar to entity beans in COM+ (called in memory database - IMDB) but dropped it in the final release due to performance problems (perhaps that is why the EJB is much slower in benchmarks as compared to COM+ and dot net). For every entity bean, you must create two different java interfaces (home interface and remote interface), and implement the component class. The component class implements the EntityBean interface. The EntityBean interface has methods called: EjbActivate – called when a bean is used from the object pool. ejbLoad – When using CMP, ejbLoad is called by container after it has loaded the bean from database. The code here could be empty for CMP. For BMP, you provide the code to load it from the database. EjbPassivate – called when a bean is released to the object pool. EjbRemove – responsible for removing an entity bean from the database. For CMP, if you want to keep the oject in database, throw a RemoveException.

10 In CMP, it is called by container before it stores the bean in the database. The code here could be empty for CMP. For BMP, you provide the code to Store it in the database. SetEntityContext – called by the container when an entity bean is created, the code stores its context in a local variable. UnsetEntityContext – called to inform the bean that it is no longer being used by the container. When you develop an entity bean class, you also write an ejbCreate method. The code here creates a new instance of the bean and initializes the attributes of the class from the database. If you are using BMP, you need to write the code to read the values from the database and copy them into the class variables. If you are using BMP, you also write several finder methods for locating the bean. For CMP, you indicate to the container how to perform queries when you configure the bean. ejbStore -

Steps in Creating an EJB:
There are 5 things that need to be done in creating an EJB. 1. Create the bean class. 2. Create the home interface. This is used to create or find an existing bean. 3. Create the remote interface. 4. Create the deployment descriptor file (all modern EJB servers now require an XML file instead of the manifest file). 5. Create the jar file. The last two steps can be accomplished by a deployment wizard. Finally you need to deploy the jar file in the application server.

Example – Entity Bean using CMP:
We will create a Student entity bean corresponding to the Students table in the StDb database.

11

Step 1: Creating the bean. Create a folder called student. Type the following file
StudentEJB.java in it. //--- StudentEJB.java --- uses CMP package student; import javax.ejb.*;

// A data object representing a student in Students table in stdb database public class StudentEJB implements EntityBean, java.io.Serializable { public int studentID; public String firstName; public String lastName; public String address; public String major; private EntityContext context; public StudentEJB() { } public StudentKey ejbCreate(int ID, String fName, String lName) throws CreateException { if ((ID == 0) || ((fName == null) && (lName == null))) { throw new CreateException( "You must supply at least ID and first or last name"); } studentID = ID; firstName = fName; lastName = lName; return null; } public int getStudentID() { return studentID; } public void setStudentID(int ID) { studentID = ID; } public String getFirstName() { return firstName; }

12 public void setFirstName(String fName) { firstName = fName; } public String getLastName() { return lastName; } public void setLastName(String lName) { lastName = lName; } public String getAddress() { return address; } public void setAddress(String addr) { address = addr; } public String getMajor() { return major; } public void setMajor(String maj) { major = maj; }

//--- EntityBean interface methods. For CMP, these could be empty // except for set/getEntityContext public void ejbActivate() { } public void ejbPassivate() { } public void ejbLoad() { } public void ejbStore() { } public void ejbRemove() { } public void setEntityContext(EntityContext aContext) { context = aContext; }

13 public void unsetEntityContext() { context = null; } }

Step 2: Create the Home interface. This is used by the client to either create or locate a
bean. Type the following in a file called StudentHome.java. Note that the Home interface must contain a create method with the same signature as the ejbCreate method in the bean class except that the create method throws the RemoteException. //--- StudentHome.java --package student; import javax.ejb.*; import java.rmi.RemoteException; import java.util.*; public interface StudentHome extends EJBHome { public Student create(int ID, String firstName, String lastName) throws RemoteException, CreateException; public Student findByPrimaryKey(StudentKey key) throws FinderException, RemoteException; public Collection findByLastName(String lastName) throws FinderException, RemoteException; public Collection findByFirstName(String firstName) throws FinderException, RemoteException; public Collection findByMajor(String major) throws FinderException, RemoteException; }

Step 3: Creating the remote interface. Create a file called Student.java as shown below.
All the methods in the remote interface should have corresponding methods in the bean class. Remember the client will interact with the bean using the remote interface (recall the RMI example). //---Student.java---- remote interface package student;

14 import javax.ejb.EJBObject; import java.rmi.RemoteException; public interface Student extends EJBObject { public int getStudentID() throws RemoteException; public void setStudentID(int ID) throws RemoteException; public String getFirstName() throws RemoteException; public void setFirstName(String fName) throws RemoteException; public String getLastName() throws RemoteException; public void setLastName(String lName) throws RemoteException; public String getAddress() throws RemoteException; public void setAddress(String addr) throws RemoteException; public String getMajor() throws RemoteException; public void setMajor(String maj) throws RemoteException; } Step 4: Creating the deployment descriptor. Step 5: Creating the jar file. Step 6: Deploying the EJB.

Creating the Client:
Create a jsp file called StudentClient.jsp as shown below: <%@ page language="java" import="javax.naming.*,student.*" %> <%@ page import="javax.rmi.PortableRemoteObject,java.util.*" %> <html> <body> <pre> <% try { Context initial = new InitialContext(); Object studentRef = initial.lookup("Student");

15 student.StudentHome home = (student.StudentHome) PortableRemoteObject.narrow( studentRef, student.StudentHome.class); Student stu = home.create(857, "Ausif", "Mahmood"); out.println("Student Created"); } catch (Exception exc) { exc.printStackTrace(new PrintWriter(out)); } %> </pre> </body> </html>

Example of an Entity Bean using BMP (Bean Managed Persistence):
When using BMP, you need to write the database code in ejbCreate, ejbLoad, ejbStore, and ejbRemove methods. You also need to provide some finder methods. The result is data driven object models (yeuch) or difficulty in implementing a non-trivial best practice domain object model using entity beans and container managed persistence. In many cases the proprietary persistence tools offer better solutions. Various attempts have been made to overcome these shortcomings using the other blend of EJB, Session beans, in conjunction with a proprietary persistence tool but none of these approaches are standardized.

Communication services
An enterprise system must manage communications between client machines and server applications, between server applications on the same machine and on different machines within an enterprise, and between the servers of multiple enterprises. EJB's use a number of standard Java API's to provide these services. The JNDI naming service is used to find remote references to factory objects used to create, retrieve and delete EJB's. The factory objects are remote objects implementing an EJB's Home Interface. The only way to invoke an operation on an EJB is via it's Remote Interface. The RMI over IIOP protocol and API are used for invoking operations on EJB's via their remote and home interfaces. Again there is little new here except a standardizing of the use of Home and Remote interfaces. The implementation of the standard EJB Home and Remote interfaces pollutes a Problem Domain class with a large amount of EJB specific code (yeuch - but most distributed object architectures do similar things). Remote objects also require artificially large grain

16 operations to avoid large numbers of network calls that result in poor performance (yeuch - but again most distributed object architectures require the same). Thankfully J2EE provides the JSP/Servlet API's and services that are an excellent alternative approach to client/server communications when menu-driven, form-oriented user interfaces are sufficient.

Transaction services
Probably the biggest advantage gained from using EJB's is its support for declarative transaction management. It is no longer necessary to program explicit transaction control using fairly complex API's like OMG's Object Transaction Service, its Java implementation, JTS or your own API. Instead transactional characteristics of objects are declared in deployment descriptors. Nothing new again - Microsoft was here first with their MTS product. Changing transactional behavior no longer requires changes to source code. Objects of the same class can be deployed with different transactional characteristics in different applications. The responsibility for correct transactional behavior now falls to the assembler or deployer of the EJB's instead of the developer. The developer does need to consider how her bean might react with different transaction characteristics and code and test appropriately; adding flexibility always adds to the number of paths that need to be tested. Declarative transaction management does little to help resolve isolation level and pessimistic vs optimistic locking issues and these capabilities can vary across application servers and databases.

Security services
Authentication Critical to any set of security services is the ability of the system to establish the identity of a user. End-users of enterprise systems like to have a single-sign-on where they provide confirmation of their identity once. Most enterprise applications however, require a user to identify themselves each time they start the application. This leads to multiple user ids and multiple passwords (with different rules about what makes a good password) per user - inconvenient for the user, a headache for system administrators ... but heaven for that special breed of data security officer that would prefer people did not use a system at all (thus keeping the data completely secure) :-) Authentication is not specified in either the EJB specification or the J2EE client component specification. This makes this area subject to vendor specifics. A common approach when using EJB's is to use the JNDI API to provide authenticating information to access a server or resources on a server. A future version of J2EE may require the use of the Java Authentication and Authorization Service (JAAS).

17 Authorization Authorization is the ability of a system to restrict what each user can see and do. There are at least three variables in authorization of a non-trivial enterprise application: 1. user role 2. object ownership 3. object state User role based security assigns each user to one or more roles. Each role is given specific permissions and/or capabilities. EJB's provide a declarative role-based security mechanism. Each role is granted access to methods of classes by declarations in deployment descriptors. However, method level is often too granular and an administrative headache where multiple methods exist to perform the same operation in slightly different ways. In many cases, a role is allowed to see objects in a class or not, update objects in a class or not and delete objects in a class or not - but this level of granularity is not supported by EJB's. More complicated security rules depend on whether or not the user owns an object (maybe they created it, or they are assigned to a team that created it). It gets even more complicated when access depends also on the state of the object. For example, once submitted to a manager, an owner may not be able to update their object anymore. The only support provided by EJB's for this sort of authorization is a container supplied method to inquire if a user belongs to a certain role. Many organizations are looking at business rules engines to help manage these more complex access rules. Auditing Recording who did what and when they did it is a common requirement within business systems especially where financial transactions are involved. EJB's do not provide any specific help in this area and can be a distinct hindrance given their restrictions on writing to files. The JMS messaging API can be used to send messages to a logging service.

Performance
A general rule of thumb is, "The more generic a solution, the slower the performance". EJB's are no exception. The overheads of the EJB container services are significant. Where user numbers and usage patterns benefit from EJB's resource management capabilities this performance overhead may be offset. Specifically, EJB containers may reuse instances from pools of objects to reduce the overhead of creating and destroying objects. An EJB container may also unload (passivate) and reload (activate) beans from/to memory to reduce memory usage. Obviously different vendors EJB containers

18 and servers perform differently making the choice of vendor important (and the pain of switching vendor more likely to be felt).

Design Patterns
Another big issue with EJB's are the restrictions on writing re-entrant code; that is code from bean A that calls bean B which then calls back on bean A. Call backs are used in many popular OO design patterns but EJB's currently make it hard to use call backs.

Summary
This has been a very short introduction to each of the enterprise system services above. I hope to expand on each one in future issues with help from my colleagues at TogetherSoft and your feedback. Java's big claim was 'Write Once, Run Anywhere' and today it largely lives up to that claim. However, EJB's do not! To run Enterprise Java Beans, we are required to have an application server product written by a third party vendor. The EJB 1.1 specification, although tighter than 1.0 still allows for numerous variations between different vendors' EJB Containers and application servers. Anyone who has had to switch application server products during development knows that it is not straightforward. However, as the standard matures this problem will hopefully decrease. Much work remains before EJB's become a generic solution that meet 80% of developers' needs. The biggest contribution EJB's and J2EE technology are likely to make is the standardization of the interfaces to these commonly needed services. Where it fits, EJB technology is there to be used today but, as always, developers need to continue to pick the right tool for the job.


				
DOCUMENT INFO
Shared By:
Categories:
Stats:
views:52
posted:11/29/2009
language:English
pages:18
Jun Wang Jun Wang Dr
About Some of Those documents come from internet for research purpose,if you have the copyrights of one of them,tell me by mail vixychina@gmail.com.Thank you!