JPA in practice

L

Lew

JPA (Java Persistence API) makes promises about injection of references and
behavior through magic annotations like @Entity and @PersistenceContext. To
keep those promises, JPA apps must deploy into containers that know how to
inject, like GlassFish or Spring or (supposedly) Java Server Faces (JSF). You
can still use JPA without injection in a leaner Tomcat environment.

The key enablers to JPA are EntityManagerFactory and EntityManager. You
define a bunch of @Entity classes to pull database information into your
object model as value objects. Logic instances, i.e., business processes that
use these entities need an EntityManager to bind the objects to their data
store backing. For non-injected environments like plain Tomcat, you use a
static method to create the factory:

public class Util
{
private static final String PUNIT = "projectPU";
private static final EntityManagerFactory EMFCANON =
Persistence.createEntityManagerFactory( PUNIT );

public static EntityManagerFactory getEmf()
{
return EMFCANON;
}
}

The factory will be heavy but thread safe. Request processors get their
lightweight, non-thread-safe EntityManagers from the common factory:

public class BizProcess
{ ...
public String submit()
{
EntityManager emgr = Util.getEmf().createEntityManager();
try
{
Entity e = new Entity();
fill( e );
emgr.getTransaction().begin();
emgr.merge( e );
emgr.getTransaction().commit();
}
finally
{
emgr.close();
}
}
}

Not as sexy as @PersistenceContext() but it works.
 
A

Arved Sandstrom

Lew said:
JPA (Java Persistence API) makes promises about injection of references
and behavior through magic annotations like @Entity and
@PersistenceContext. To keep those promises, JPA apps must deploy into
containers that know how to inject, like GlassFish or Spring or
(supposedly) Java Server Faces (JSF). You can still use JPA without
injection in a leaner Tomcat environment.

The key enablers to JPA are EntityManagerFactory and EntityManager. You
define a bunch of @Entity classes to pull database information into your
object model as value objects. Logic instances, i.e., business
processes that use these entities need an EntityManager to bind the
objects to their data store backing. For non-injected environments like
plain Tomcat, you use a static method to create the factory:

public class Util
{
private static final String PUNIT = "projectPU";
private static final EntityManagerFactory EMFCANON =
Persistence.createEntityManagerFactory( PUNIT );

public static EntityManagerFactory getEmf()
{
return EMFCANON;
}
}

The factory will be heavy but thread safe. Request processors get their
lightweight, non-thread-safe EntityManagers from the common factory:

public class BizProcess
{ ...
public String submit()
{
EntityManager emgr = Util.getEmf().createEntityManager();
try
{
Entity e = new Entity();
fill( e );
emgr.getTransaction().begin();
emgr.merge( e );
emgr.getTransaction().commit();
}
finally
{
emgr.close();
}
}
}

Not as sexy as @PersistenceContext() but it works.
If your client happens to still be wedded to OAS 10g (oc4j 10.1.3), with
EJB 2.5 (the best way to put it), and JSF 1.1, you still have to forgo
some of those nice annotations, and do things like you describe above. :)

We're pushing them to switch to Weblogic...it's a hard slog. These are
people that still use IE 6.

AHS
 
T

Tom Anderson

public class Util
{
private static final String PUNIT = "projectPU";
private static final EntityManagerFactory EMFCANON =
Persistence.createEntityManagerFactory( PUNIT );

public static EntityManagerFactory getEmf()
{
return EMFCANON;
}
}

The factory will be heavy but thread safe. Request processors get their
lightweight, non-thread-safe EntityManagers from the common factory:

public class BizProcess
{ ...
public String submit()
{
EntityManager emgr = Util.getEmf().createEntityManager();
try
{
Entity e = new Entity();
fill( e );
emgr.getTransaction().begin();
emgr.merge( e );
emgr.getTransaction().commit();
}
finally
{
emgr.close();
}
}
}

Not as sexy as @PersistenceContext() but it works.

Is there a convenient way to write code that gets an injected
EntityManager in a managed environment, but arranges its own provision in
an unmanaged one? Is that a meaningful thing to ask for?

tom
 
L

Lew

Tom said:
Is there a convenient way to write code that gets an injected
EntityManager in a managed environment, but arranges its own provision
in an unmanaged one? Is that a meaningful thing to ask for?

I have a way, but I won't know if it works until I succeed at getting an
injected one. Then I can compare the two scenarios.

For the factory:

public class Persistuff
{
public static final String PUNIT = "projectPU";

@PersistenceUnit( unitName=PUNIT )
private static EntityManagerFactory emf;

private static final EntityManagerFactory EMFCANON =
Persistence.createEntityManagerFactory( PUNIT );

public static EntityManagerFactory getEmf()
{
return (emf == null? EMFCANON : emf);
}
}

For the manager:
<http://java.sun.com/javaee/5/docs/tutorial/doc/bnbrm.html#bnbrp>

public class Bizzniss
{
@PersistenceContext
private EntityManager em;

public void run()
{
EntityManager mgr = (em != null? em
: Persistuff.getEmf().getEntityManager());
// use 'mgr' here
}
}

Unknown: resource consumption and packratting caused by injected values, if any.

Learning how to do this, I was running Glassfish 3 with a Postgres back end,
but my 4 GB RAM server box's power supply just gave up the ghost. Turns out
the combination of GF and PG with NetBeans was too much for my poor
single-core 64-bit workstation with only 1 GB RAM. Then I tried the
non-injective approach with Tomcat, Postgres and NetBeans. Turns out that
runs just great on the workstation.

That triggered a major "Hmmm." I may be on to a way to develop, deliver and
deploy full-blown custom apps very quickly with very low administrative and
hardware overhead.

Looks like JSF, JSP, JPA and servlets on Tomcat are a winning combination.
Once you factor in a few quirks.

(Bonus - Tomcat plays well with other environments like Apache Web Server and
many Java EE application servers.)
 
A

Arved Sandstrom

Lew said:
I have a way, but I won't know if it works until I succeed at getting an
injected one. Then I can compare the two scenarios.

For the factory:

public class Persistuff
{
public static final String PUNIT = "projectPU";

@PersistenceUnit( unitName=PUNIT )
private static EntityManagerFactory emf;

private static final EntityManagerFactory EMFCANON =
Persistence.createEntityManagerFactory( PUNIT );

public static EntityManagerFactory getEmf()
{
return (emf == null? EMFCANON : emf);
}
}

For the manager:
<http://java.sun.com/javaee/5/docs/tutorial/doc/bnbrm.html#bnbrp>

public class Bizzniss
{
@PersistenceContext
private EntityManager em;

public void run()
{
EntityManager mgr = (em != null? em
: Persistuff.getEmf().getEntityManager());
// use 'mgr' here
}
}

Unknown: resource consumption and packratting caused by injected values,
if any.

I wouldn't bother to do the above, but in response to Tom's question the
above is what I would do. If that makes any sense. :)

After all, there are no classpath issues - Java knows about the
annotations. All that happens, from observation, is that if in a given
situation that injection doesn't work then it doesn't work, and you
proceed and use the other approach(es).

My gut feeling is that if injection doesn't work then there's not much
penalty. For example, if your version of JSF doesn't support specific
annotations then nothing happens when you inadvertently use them.

I simply haven't bothered doing anything like the above because I never
write J2EE apps where it's not already known exactly what the
environment is. And if the environment ever changes there'll be major
advance notice.
Learning how to do this, I was running Glassfish 3 with a Postgres back
end, but my 4 GB RAM server box's power supply just gave up the ghost.
Turns out the combination of GF and PG with NetBeans was too much for my
poor single-core 64-bit workstation with only 1 GB RAM. Then I tried
the non-injective approach with Tomcat, Postgres and NetBeans. Turns
out that runs just great on the workstation.

That triggered a major "Hmmm." I may be on to a way to develop, deliver
and deploy full-blown custom apps very quickly with very low
administrative and hardware overhead.

Looks like JSF, JSP, JPA and servlets on Tomcat are a winning
combination. Once you factor in a few quirks.

(Bonus - Tomcat plays well with other environments like Apache Web
Server and many Java EE application servers.)

We ourselves (me and the other folks at the small consulting company I
work for) have internally arrived at much the same conclusion. As in,
why bother with a full-fledged app server when you don't need it?

To your list of API's/frameworks I would also add Seam as a
consideration, for some projects.

AHS
 
T

Tom Anderson

I have a way, but I won't know if it works until I succeed at getting an
injected one. Then I can compare the two scenarios.

For the factory:

public class Persistuff
{
public static final String PUNIT = "projectPU";

@PersistenceUnit( unitName=PUNIT )
private static EntityManagerFactory emf;

private static final EntityManagerFactory EMFCANON =
Persistence.createEntityManagerFactory( PUNIT );

public static EntityManagerFactory getEmf()
{
return (emf == null? EMFCANON : emf);
}
}

For the manager:
<http://java.sun.com/javaee/5/docs/tutorial/doc/bnbrm.html#bnbrp>

public class Bizzniss
{
@PersistenceContext
private EntityManager em;

public void run()
{
EntityManager mgr = (em != null? em
: Persistuff.getEmf().getEntityManager());
// use 'mgr' here
}
}

Do you need the injection bits in Persistuff? If injection is working,
Bizzniss will get an EntityManager of its own, and never have to call
Persistuff.getEmf(). The only time it will have to call it is when there
is no injection, in which case the injected in field in Persistuff will be
null anyway. I suppose this approach means you take advantage of the case
where a EntityManagerFactory is injected but a PersistenceContext isn't.
That seems like a bit of an unlikely case to me, but i am far from an
expert on this.
Unknown: resource consumption and packratting caused by injected values, if
any.

True that.
Learning how to do this, I was running Glassfish 3 with a Postgres back end,
but my 4 GB RAM server box's power supply just gave up the ghost. Turns out
the combination of GF and PG with NetBeans was too much for my poor
single-core 64-bit workstation with only 1 GB RAM. Then I tried the
non-injective approach with Tomcat, Postgres and NetBeans. Turns out that
runs just great on the workstation.

That triggered a major "Hmmm." I may be on to a way to develop, deliver and
deploy full-blown custom apps very quickly with very low administrative and
hardware overhead.

I'm surprised GF took *so* much extra memory (and CPU?). What's it doing?

Are there any lightweight app servers that wouldn't be a big overhead over
Tomcat (or perhaps even better, Jetty)?

tom
 
L

Lew

Tom said:
I'm surprised GF took *so* much extra memory (and CPU?). What's it doing?

Are there any lightweight app servers that wouldn't be a big overhead
over Tomcat (or perhaps even better, Jetty)?

In part the answer depends on how much app server you need. Tomcat already is
an app server for web apps and web services. Arved's suggestion of Seam
<http://www.jboss.com/products/seam/>
seems promising.

Do you need EJBs? Tomcat with Apache OpenEJB might do the trick. Seam does
that, too. One day I'll test to find out, if I can figure out why I ever need
EJBs.

Do you just need dependency injection? Maybe Spring is enough (or too much -
I'm still deciding).

Do you need message queues? BPEL? Integrated JNDI? Multiple cooperating
apps or quasi-independent components? Common services for multiple enterprise
applications? Clustering or other scalability strategies?

My untested hypothesis is that there's a threshold of system complexity or
performance where the overhead of a full-blown app server like JBoss or
Glassfish is less than the difficulty of managing or scaling piecemeal solutions.

If nothing else, there's the fact that the job market requires practitioner
skill in all of that, so it behooves me to buy a new power supply for my
multi-core PC and keep practicing with full-bore Java EE.
 
R

Robert Klemme

My untested hypothesis is that there's a threshold of system complexity
or performance where the overhead of a full-blown app server like JBoss
or Glassfish is less than the difficulty of managing or scaling
piecemeal solutions.

I second that. That bad news is

1. it's difficult to determine that level of complexity

2. from my experience real world software tends to start out simple and
ends up complex

So it's probably worthwhile to consider going full JEE earlier than you
really need it.

Unfortunately those JEE containers do also have issues of their own.
The fact that JBoss introduces the third transaction manager in a
relatively short period of time gives you hints as to where they might
lie. A pity TX management is so fundamental...

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,765
Messages
2,569,568
Members
45,042
Latest member
icassiem

Latest Threads

Top