1.Thus the Sort example can be modified by renaming the bean's remote interface to SortRemote (modifying other files as needed). Then define a new interface called Sort and move the two business methods from SortRemote to Sort:
public interface SortRemote extends Sort, javax.ejb.EJBObject {
}
public interface Sort {
Vector sort(Vector v, Compare c) throws java.rmi.RemoteException;
Vector merge(Vector a, Vector b, Compare c) throws
java.rmi.RemoteException;
}
2. An alternative design is to have all your root classes to extend java.rmi.Remote, or some sub-class thereof (e.g., javax.ejb.EJBObject). So, you could change Sort to:
public interface Sort extends java.rmi.Remote {
Vector sort(Vector v, Compare c) throws java.rmi.RemoteException;
Vector merge(Vector a, Vector b, Compare c) throws java.rmi.RemoteException;
}
and then SortRemote could remain:
public interface SortRemote extends Sort, javax.ejb.EJBObject {
}
This probably is close to the previous design, and does a better
job of expressing the fact that Sort is actually a remote
interface (although not necessarily an EJB interface). It
was already implied that Sort was a remote interface, by
the fact that all its methods throw RemoteException, so
why not make it explicit?
3. An argument to not have Sort extend java.rmi.Remote is that one may want the client to use Sort and be unaware whether the object behind Sort is remote or not. This should allow one to switch between an Object By Value and a remote object mechanism without changing the client.
Let's look at an example: Let's assume we want to have a default create for the Person bean. The Home must have the following signature:
public interface PersonHome extends EJBHome {
public Person create() throws ...;
}
Now let's say we want a default create for the Employee
bean too. We would like to have:
public interface EmployeeHome extends PersonHome {
public Employee create() throws ...;
}
This is not allowed in Java. The overriding method cannot
differ only in the return type.
So, one may then try to avoid the overload on the return type, by simply inheriting the method in the base class:
public interface EmployeeHome extends PersonHome {
}
Oops! Now you have broken EJB compliance, which
states that the return type of a create must be the
remote interface.
Obviously, something has to give. What needs to give is the EJB specification, which needs to be enhanced to support inheritance of home interfaces properly. This is probably slated for EJB 2.0. For now, you cannot inherit your home interfaces.
Having said that, note that you can always inherit your remote interfaces (as in the above). Your homes still must be:
public interface PersonHome extends EJBHome {
public Person create() throws ...;
}
and:
public interface EmployeeHome extends EJBHome {
public Employee create() throws ...;
}
This is really the way to go until the EJB specification is
updated.
If there are a number of shared methods between the two intefaces, you can put the shared methods into a common base class, of course.
1) Break all service IDL into a factory and the actual implementation. This will map to Home/Remote interfaces nicely.
2) Store all your factories in CosNaming. This will map nicely to JNDI.
3) Use design patterns which mimic the EJB types: stateless session objects, stateful session objects, and entities. The corollary of this is to avoid building services which are not supportable by EJB. For example, avoid singleton objects, which are not easily supported in EJB.
Following these basic guide-lines should allow most of your services to migrate to EJB with minimal modification.
Note, however, that there is nothing wrong with using a hybrid architecture. It is reasonable to expect that some services will be easily ported to EJB, and some will be hard to port. Any EJB server built on IIOP should support hybrid deployments easily, allowing you to migrate your services over time, or in some cases, not at all.
So we reach the inevitable conclusion that EJB provides a useful set of server-side design patterns, but does not provide ALL the useful patterns. Developers will find that jumping out of EJB (presumably into CORBA) will be useful in a number of cases. And of course, our product makes this transition painless, in that it preserves the transactional semantics, and security, when crossing the EJB-CORBA boundary. This preservation of distributed system semantics is not easily doable (and is not being done by competitors' products) if the EJB container is not built on top of IIOP (e.g., CORBA).
If I execute several setXXX() methods against an entity bean as a group, I get some rather intense database activity. I was wondering if something could be done to reduce the number of SQL UPDATE calls (and perhaps their associated ejbLoads) to 1 total, as opposed to 1 per setXXX().You are missing two key concepts: (1) session beans, and (2) transactions.
It is a very bad idea to make individual set or get calls on an entity bean within its own transaction. You really want to bundle a bunch of accesses to one or more entity beans into a single transaction, thereby reducing the number of DB accesses.
The "right" way to do this is to never access your entity beans directly from you client, but always to access them though a session bean. Basically, you want to use a session bean which says "get me a bunch of information", and then this session bean can do all the getting and setting on the entity beans.
Why this design pattern? Because then you can specify "Required" as the transaction attribute on the session bean, and all the entity accesses will run in the session bean's transaction. Since each entity bean will be loaded only once per transaction (or not at all, if using caching) this will have a huge impact on your overall performance, by drastically reducing your DB access.
Another approach is to use client demarcated transactions. Here, you start a transaction on the client, access all the beans you want, and then commit the transaction. Again, since each bean is loaded and stored at most only once per transaction, this will have the same effect. However, generally client demarcated transactions are frowned upon, because it is much harder to control a client than to control the container.
One may suggest making the updates asynchronous, which is a very bad idea, because the whole idea of transactions is that you know it worked (e.g., committed) or you know it failed (e.g., rolled back). Saying "we'll try to do it, maybe later, don't worry about the results" breaks the whole model!
Of course, you could always spawn off a client thread which does the client- demarcated transaction commit asynchronously, if you are in a hurry, and come back to poll the results later.
You could prevent two transactions occuring at the same time by carefully specifying the transaction contexts, but this seems like its destined to be a nightmare to maintain or debug.
Also one should never pass the EJB implementation's "this" pointer as a parameter. To obtain a valid reference to an EJB, you need to call:
context.getEJBObject();
where context is either a SessionContext, or an EntityContext.