J2EE patterns: Dynamic Proxy for Local and Remote Interface (EJB 2.0)
With the introduction of local interface in the new EJB 2.0 spec, one question arise: Is it possible to create a session bean that can use both local and remote interface?
- Posted by: Kjetil Helle
- Posted on: August 03 2001 11:30 EDT
Why do we want that?
Well, consider this: Your company has a solution that works with Borland BAS 4.5 appserver (which supports EJB 1.1). The solutions requires the use of BAS O/R mapping tool to model the relationships between entities. But BAS 4.5 costs money, especially for small enterprises. So your company is looking for ways to lower the investment costs for potentially new customers. It decides to port their solution to EJB 2.0 and use JBoss, a free Open Source appserver, together with MVCSoft's Persistence Manager, which allows you to deploy standard EJB 2.0 JAR files on JBoss.
But what impact does this have on the entity bean relationships and interfaces of your solution? EJB 2.0 states (amongst other things) that only entity beans that implements local interfaces (javax.ejb.EJBLocalObject and javax.ejb.EJBLocalHome) can participate in a ejb-relationship. This means that you would have to have two sets of entity ejbs. One set for EJB 1.1 and a second set for EJB 2.0. But would that mean two sets of session ejbs as well?
Unfortunately, all methods in the remote component interface MUST throw java.rmi.RemoteException. All methods in the local component interface MUST NOT throw java.rmi.RemoteException. At a glance it could seem that it would mean two sets of session ejbs. If your session beans uses entity beans directly (by directly I mean for instance the session beans import interfaces of entity beans), the quick and dirty route would be to have two sets of session ejbs as well. But this is far from ideal regarding reuse, maintenance and portability.
So what's the idea then? The idea is to use the DynamicProxy class to manufacture a single class that implements both your local and remote interface. Within the method invocation handler, use reflection to match up to the appropiate method. You should hardly need to change your implementation code at all, you would just use a factory class to create the DynamicProxy.
The idea requires JDK 1.3 or above. I haven't tried this, but it should probably work. So comments, suggestions, and implementation experiences are very welcome!
Thanks to Dan O'Connor for his insightful ideas!
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by alain hsiung on August 05 2001 12:11 EDT
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by Fred Loney on August 14 2001 19:28 EDT
- Dynamic Proxy for Local and Remote Interface (EJB 2.0 by eric chavet on July 01 2005 13:24 EDT
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by Donnie Hale on August 20 2001 16:00 EDT
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by Kjetil Helle on August 26 2001 12:02 EDT
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by Harsh K on November 07 2001 09:17 EST
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by Kjetil Helle on August 26 2001 12:02 EDT
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by Chen ChunSong on March 04 2002 21:47 EST
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by simon r on March 18 2002 21:51 EST
- Dynamic Proxy , Reflection, Local & Remote i/f by Sri Ramanujam on April 30 2004 21:18 EDT
- Dynamic Proxy for Local and Remote Interface (EJB 2.0) by Fixation Author on November 17 2005 13:38 EST
The only "problem" with dynamic proxy generation of EJBean is that the new generated EJBean (the one that provides both the local and the remote EJB interfaces) has to be
deployed in the deployement descriptor as a new EJBean.
With the DynamicProxy API you can generate such an EJBean proxy but you cannot control the name of its class nor enter it in the deployment descriptor instead of the original EJBean. The client has to refer to (get the home from) the EJBean proxy instead of the original!
We have written such a tool that deploys proxy EJBeans automatically, but it is NOT dynamic (i.e. at runtime). It cannot for the architectural reasons mentioned earlier (it would be against the EJB separation between deployment and runtime phases).
Basically we've implement an interceptor architecture for any EJB container. I know, JBoss has its own -and this is a good thing!- It has been mainly used with Weblogic. Interceptors have been standardized since Corba but used in distributed systems long before. DynamicProxy in Java is very elegant to implement client side and server side interceptors or any proxy design patterns. But the architecture of EJB is more static and force to declare the "servers" (EJBeans) before runtime. So I still have no idea to make EJBean proxies dynamic.
Please let me your ideas and comments.
As I understand it, the context of this pattern is a requirement to distribute either a remote or local variant of an EJB. The driving force of this pattern is to use a single SessionBean code source that discriminates among the variants. The local vs. remote EJB choice is a deployment choice and always requires a deployment configuration change, as the respondent indicates. Despite the need to change the deployment descriptor, it is still advantageous to have a solution that uses a single Session Bean source code base.
The dynamic proxy solution binds the variant at run-time. It is, however, sufficient to bind the variant at compile-time. Aspects (www.aspectj.org) present a compile-time binding alternative to the dynamic proxy solution. There is an example that exactly fits the pattern at http://aspectj.org/doc/primer/examples/timeserver/index.html. This example shows how to augment source code to handle remote exceptions.
The aspect solution to the ejb choice runs as follows. Define two aspects LocalEjbAspect and RemoteEjbAspect that introduce the desired ejb behavior to all affected Session Bean source files at compile time. The same aspect could also introduce the correct extends clause and throws clauses into a common set of Entity Bean interface source files.
The result is that the local or remote ejb variant is bound at build time with the necessary code confined to two clearly delineated cross-cutting aspects, with minimal coding effort and a single EJB source base.
If you have found a solution to this problem, please tell me.
A couple of comments:
1) Practically speaking, an entity bean shouldn't have a component (the new term for "remote") interface. That's been pretty well documented in terms of effective EJB design.
2) More fundamentally, the EJB implementation class DOES NOT implement the component interface (i.e. there's no "implements" clause in the class declaration). Correspondingly, the methods in the implementation class should not have a "throws RemoteException" specification. You mention Borland AppServer - if you run its verifier in verbose mode, you'll get warnings that including a "throws RemoteException" on EJB method implementations is deprecated.
So it doesn't matter that the throws clauses on the component and local interfaces are different. It's the deployment descriptor that ties together Component interfaces, Local interfaces, Home interfaces, and EJB implementations.
The only thing I'm not fond of is that I have to maintain a semantic interface in two different places (the Component one and the Local one). This does add flexibility, though, in that they don't have to each have the exact same set of methods.
2) More fundamentally, the EJB implementation class DOES NOT implement the component interface (i.e. there's no "implements" clause in the class declaration). Correspondingly, the methods in the implementation class should not have a "throws RemoteException" specification. </snip>
First of all, sorry if I get too implementation specific, I only do this to try to explain what I am saying.
If you read my post closely, I was writing about the component interfaces and _not_ of the implementation class.
The problem described occurs if a session bean (or any other class for that sake) whishes to use an entity bean. The class has to state wheter it uses the remote or the local interface. The two interfaces are different in ways like that the remote interface extends the EJBObject but the local interface extends the EJBLocalObject, and the remote interface has a throw clause but the local doesn't. Because of these differences the easy way (but perhaps not the "best") would be to make two seperate sets of for example session beans.
I don't know of a trivial solution to this, but If you got one please tell me! :)
One interesting thing, that seemingly got lost in this thread of dicsussion, was the author's allude to mainating an existing (set of) (Entity) Interfaces' using EJB 1.1 yet migrating them to EJB 2.0 for purposes of using the new Entity relationship model (and preserving business expenses).
To me then this is not a realistic design pattern. You (should try to) design your Entity Beans for local use (ideally). EJB 2.0 further facilitates that.
The question of re-using an existing set of EJBeans (regardless of their being session or entity) with both Local and Remote *Components* across clients that can distinguish between them is a little more tricky.
By design the EJB (now J2EE) spec authors seem to intend for the deployment mechanism to decide disparate local/remote components (of course you can have your entity component implement both as well which probably will destroy the savings from managing relationships through *cheaper* alternatives but .. we only care about the pattern ;) ) - which therefore points towards different client base. Of course you can choose to use reflection of the metadata before getting into it's specific methods and thereby employing appropriate catches - which is employed using the DynamicProxy.
I say this with no malice or offense whatsoever - Is his really a pattern for a design?
I think your pattern provide a good idea to resolve this problem.
But there has one problem which protect me from using this pattern. I wish I can get the answers from all experts.
Everybody know,if an entity bean want to provide the remote and local interface, it must declare both the remote component interface and local remote interface and also the two interfaces may have the same set of methods which have the same method name and the same paramter signature except the throw clause.If a dynamic proxy implements the two interfaces, and when a method invocation is made on this proxy, the proxy can't determine the correct interface through which the method invocation is performed,So when the dynamic proxy dispatch this method invocation to the invocation handler,the declaring class of the method which is passed to the invocation handler will be the interface which is implemented by the dynamic proxy and is the first interface containing the method which have the same signature as invoked method.
So how you gurantee you will perform the correct method invocation???????????????????????? .
I think this feature should be provided by the app server, as the case with WL.
"WebLogic Server includes an optimization to improve the performance of Remote Method Interface (RMI) calls within the server. Rather than using pass by value and the RMI subsystem's marshalling and unmarshalling facilities, the server makes a direct Java method call using pass by reference. This greatly improves performance: this mechanism is also used for EJB 2.0 local interfaces."
IT is a good idea architecturally to use reflections to decide at run time to use local/remote interfaces. Given this stuff is arcane, can you pl. provide a simple example covering the whole spectrum of issues. I think the bean implemenation is trivial but it haunts you when it comes to deployment, JNDI context resolution, client etc. It will be really great if u could provide a very simple complete implementation covering:
- client program(java), client deployment, JNDI, local/remote classes, and depl desc for both being used at the same time.
I'm still interrested by this topic but can't manage to implement the proxy solution.
If I understood, the proxy will hide the instance of the EJB object. But the problem remains the same besause of the two different interfaces ? Am I wrong ?
I was hoping to see an easy solution to the problem, but alas none seems evident thus far. I have an application that uses stateless EJBs with both local and remote interfaces. The Sun One App. server apparently doesn't do as much checking on EJBs at WebLogic 8.1 does. When I try to deploy the EJBs under WLS, it complains of the RemoteException defined in the bean's implementation class but not declared in the local home interface. Does anyone know if there's an WLS deployment option to disable this check?