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                                                Skeleton
            Object                                              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 stub-
skeleton 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


ejbStore -    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.


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:51
posted:3/8/2010
language:English
pages:18