views:

42

answers:

1

This is a pretty newbie question- please know I'm aware of that.

I have a stateless session bean that needs to load up some data once and cache it locally in a static variable for use by all instances of that bean. The data can be accessed through an entity bean. I'm wondering if its safe to cache the entity instance, or if I should clone it. Also, this entity also has sub-entities.

Call the entity Foo. A Foo has a Bar. In my session bean, I'd like to do something like this:

private static final FOO_ID = 123L;

private static Foo foo;

private static Foo getFoo(EntityManager em) {
    if (foo != null)
        return foo;
    return foo = (Foo) em.find(Foo.class, FOO_ID);
}

public void someBusinessMethod() {
    EntityManager em = Container.getInstance().getEntityManager();
    Foo foo = getFoo(em);
    Bar bar = foo.getBar();
    // do some stuff with foo and bar
}

My questions:

  1. Is this a bad idea? Will it even work?

  2. Is there a better way to load the Foo data once, possibly without need for that getFoo() method? Doing it statically when the Session class is loaded would seem to be ideal.

New (accurate) sample code, per comments:

public class Foo {   // entity
    private Long id;
    private String name;
    // getters and setters
}

public class Bar {   // entity
    private Long id;
    private String name;
    // getters and setters
}

public class FooHelper implements Helper {
    private static final long FOO_ID = 123L;
    private Foo foo;
    public FooHelper() {
       // use FOO_ID to look up a Foo & cache it locally
    }
    @Override
    public void addBar(EntityManager em) {
        Bar bar = new Bar();
        bar.setName(foo.getName());
        em.persist(bar);
    }

public class StatelesSessionBean {
    private static final Helper helper = new FooHelper();
    public void someBusinessMethod() {
        @PersistenceContext
        EntityManager em;
        helper.addBar(em);
    }
}
+2  A: 

Non final static fields are not allowed in Stateless Session Beans (SLSB). From the EJB3 specification, section 21.1.2:

An enterprise bean must not use read/write static fields. Using read-only static fields is allowed. Therefore, it is recommended that all static fields in the enterprise bean class be declared as final.

This rule is there to ensure consistency when distributing instances across multiple JVMs.

So not really a good idea. My suggestion would be to rely on the second level cache that your JPA provider may support and let him handle that transparently.

As a side note, I really wonder why you have this line in your bean:

EntityManager em = Container.getInstance().getEntityManager();

In a managed environment, you should use a container-managed entity manager and get it injected in your SLSB (using the @PersistenceContext annotation).

Pascal Thivent
In retrospect, my sample code doesn't accurately reflect what I'm trying to do. Will append new sample to original post.
Basically my question is how to accomplish the commented portion of FooHelper's constructor.
@user190758 My answer still applies: use the second level cache feature of your JPA provider to cache the `Foo` entity *transparently* for you. That's the way to go.
Pascal Thivent
So just go ahead and fetch it each time, then rely on the underlying layers to keep a copy in memory and not access the db unless its really necessary. Works for me.
@user190758: Exactly, that's it.
Pascal Thivent