Caching EJB Home references

Discussions

EJB design: Caching EJB Home references

  1. Caching EJB Home references (8 messages)

    One problem with caching and reusing EJB homes involves handling stale cached homes.
    If a client caches an EJB home and the container shuts down and then returns, the client’s cached value is stale and will not work, resulting in a CORBA exception.
    Is there any strategy wherein one could check whether the cached EJB Home reference is stale?

    Threaded Messages (8)

  2. Caching EJB Home references[ Go to top ]

    We call create() in some base class (a kind of a Remote factory for stateless Session Beans) and catch java.rmi.NoSuchObjectException as well as java.rmi.MarshalException. After catching one of those exceptions we do the Home lookup again. This scheme worked for us and is transparent for the client as long as the second lookup succeeds.

    Regards,
    Stefan
  3. Caching EJB Home references[ Go to top ]

    Could you be more specific?
  4. Caching EJB Home references[ Go to top ]

    I believe he meant something like this:

    [start pseudo-code]
    ...
        String ejbName = "...";
        EJBObject ejb = null;

        // get a home interface either from cache or over JNDI
        EJBHome home = cachedHomes.get(ejbName);
        if (home == null) {
            home = SomeJNDIHelper.lookupHome(ejbName);
            cachedHomes.put(ejbName, home);
        }

        try {
            // try to use the cached home interface
            ejb = (EJBObject) home.create();
        } catch (Exception e) {
            // stale home? make a new lookup
            home = SomeJNDIHelper.lookupHome(ejbName);
            cachedHomes.put(ejbName, home);
            // try again
            ejb = (EJBObject) home.create();
        }
    ...
    [end pseudo-code]
  5. Caching EJB Home references[ Go to top ]

    Yes, that's the basic idea. We only catch the two exceptions mentioned above, any other exception is wrapped and rethrown to the client. Though, I can't remember where I've read that these are the only exceptions to be considered for stale Homes (perhaps the spec?). If the second lookup fails, we give up (wrap and rethrow). That scheme worked for us on WAS 3.5, WLS 5.1 and 6.1

    However, be careful with WAS 3.5, I remember that we had some problems there with JNDI caching wich was introduced with Fixpack 3.

    Regards,
    Stefan
  6. Caching EJB Home references[ Go to top ]

    You seem to suggest that the only way to check if a home reference is stale is to check if it is null.
    But does the restarting of the app server make the home reference null, or makes it invalid?
    -- My Implementation --

    All clients requiring a home reference contact the ServiceLocater class which caches these references. The ServiceLocater class returns a home reference either from the cache or does a lookup. Beyond this point it is upto the callee to handle the home reference properly.
    I guess the proper implementation would be for the ServiceLocater class itself to check for the validity of the cached home reference, and if the restarting of the app server does not make these home references null, how is one suppossed to check for their staleness?
  7. Caching EJB Home references[ Go to top ]

    As far as I know, the only way to detect a stale EJBHome is to test it by calling EJBHome.create().
  8. Caching EJB Home references[ Go to top ]

    <quote>
    I guess the proper implementation would be for the ServiceLocater class itself to check for the validity of the cached home reference
    </quote>

    Exactly, this is what our imlementation does. That's why I called it "Remote Factory" - it hands out Remote stubs to the client. Home caching is done internally and the test for staleness is done by calling create(). That's very simple provided you don't need arguments for create().

    Note that a stale home won't be null, it is simply unusable. You could also try to call a method like getEJBMetaData(), but I'm not sure if that works.

    Regards,
    Stefan
  9. Caching EJB Home references[ Go to top ]

    The remote home is, for all due effects a CORBA remote reference (or an encapsulated bridge thereof). As is the Remote EJB reference. This means that a PortableRemoteObject.narrow(object,homeOrRemoteClass) should actually invoke at least one CORBA method on the remote endpoint (the method _is_a(...) from the org.omg.CORBA.Object class : http://docs.oracle.com/javase/1.4.2/docs/api/org/omg/CORBA/Object.html#_is_a%28java.lang.String%29). It could still involve a call to the method _non_existent()... In either case, this could be better than the call to the getEJBMetadata that was suggested before.

    This means that checking for the validity of a remote EJB Home or EJB is just a matter of repeating the remote casting procedure, which will actually invoke one of the least heavy operations on the remote container (also light in terms of network calls).

    In either case, for every remote EJB call, this could mean a call to PortableRemoteObject.narrow on the remote EJB, which might not be practical as it would make 2 calls per business invocation (one for the is_a and other for the real business method). As such, it would probably be better to wrap the EJB Home or EJB Remote reference in a dynamic java Proxy object with an invocationhandler that deals with possible exceptions, repeating the "create" or even the "lookup" and repopulation of the cache in case the remote call fails on any of the objects (remote home or remote ejb). This means trying to catch any exception from any remote call, checking the root cause of the thrown exception and verifying:

    1. That one of the exceptions in the hierarchy is of type org.omg.CORBA.SystemException (http://docs.oracle.com/javase/1.5.0/docs/api/org/omg/CORBA/SystemException.html)

    2. That this SystemException has its completed attribute equal to CompletionStatus.COMPLETED_NO (http://docs.oracle.com/javase/1.5.0/docs/api/org/omg/CORBA/CompletionStatus.html#COMPLETED_NO).

    In all other cases of CompletionStatus.COMPLETED_MAYBE or CompletionStatus.COMPLETED_YES, the call CAN NOT be repeated, but the object may still be cleared from any cache, re-lookep up and made available. The beauty of such a solution is that you can even begin cachng the remote ejb reference in case it is stateless, and hence improve the performance quite a bit by avoiding unnecessary calls to ejbHome.create, PortableRemoteObject.narrow and JNDI lookup. And the "client" code doesn't even see the difference because your InvocationHandler and Proxy class handle all the complexity behind the scenes.

     

    Best regards