users@glassfish.java.net

Container based Entity Manager problem/question in EE6

From: NBW <emailnbw_at_gmail.com>
Date: Tue, 23 Feb 2010 21:17:25 -0500

Hi -

I have an EE6 Jersey/CDI/JPA2 application which is packaged as a WAR
and deployed to GFv3b74.2. It's a pretty simple test app. The entry
point is a ReST resource that looks like this:

@Path("/test/")
@RequestScoped
public class HelloWorld {

@Inject
PersonBean myPersonBean;

@Context
UriInfo uriInfo;

@Get
@Produces("text/plain")
@Path("/clickMe")
public String getClicked() {
  Person aPerson = new Person();
  aPerson.setName("John Smith");
  myPersonBean.create(aPerson);
  return "Created a new person";
}

Then I have the PersonBean class that looks like this:

@Named("personbean")
@RequestScoped
public class PersonBean {

  @PersistenceContext(unitname = "myEmbeddedDerby-PU")
  EntityManager em;

  public void create(Person aPerson) {
    em.persist(aPerson);
  }

....

My Person entity class is pretty straight forward:

@Entity
public class Person implements Serializable {

  @Id
  @GeneratedValue
  private long id;

  @NotNull
  private String name;

  getters/setters/etc

.....

I am trying to use the Container-Managed Entity Manager. The relevant
bits of my persistence.xml look like this:

<persistence-unit name="myEmbeddedDerby-PU" transaction-type="JTA">
  <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
  <jta-data-source>jdbc/__MyTestDBPool</jta-data-source>
  <exclude-unlisted-classes>false</exclude-unlisted-classes>
  ...
</persistence-unit>

I have an empty beans.xml, and my web.xml simply contains references
to the Jersey servlet.

I'm using an embedded Derby JDBC connection pool / resource which I
created like so:

asadmin create-jdbc-connection-pool --datasourceclassname
org.apache.derby.jdbc.EmbeddedDataSource --restype
javax.sql.ConnectionPoolDataSource --property
"databaseName=\$\{com.sun.aas.instanceRoot\}/databases/mytestdb:connectionAttributes=\;create\=true"
MyTestDBPool

2. Cause the DB to get generated by pinging it

asadmin ping-connection-pool MyTestDBPool

3. Create the JDBC resource

asadmin create-jdbc-resource --connectionpoolid=MyTestDBPool jdbc/__MyTestDBPool

So - when I run this application and I get the follow exception at
em.persist(aPerson):

javax.persistence.TransactionRequiredException

On a hunch I tried injecting a UserTransaction into my PersonBean like so:

@Resource
private UserTransaction utx;

Then changing my create method like so:

try {
  utx.begin();
  em.persist(aPerson);
  utx.commit();
.....

That worked and caused my entity to be persisted, however, that
indicates that I am using an Application-Managed Entity Manager
instead of my desired Container-Managed Entity Manager.

Any thoughts on what am I missing here to enable using the
Container-Managed Entity Manager.

...

Actually, before I hit post I went off and did some more digging and
on a hunch I turned by PersonBean into a Stateless EJB Session bean by
removing @RequestScoped and adding @Stateless, the I changed how it
was being injected into the ReST resource by changing @Inject
PersonBean myPersonBean to @EJB PersonBean myPersonBean et voila it is
working in a Container-Managed fashion.

So this leads me to the question, why was the RequestScoped CDI bean
not providing a container managed EM w/transactions? Are EJBs the only
EE components which do?

While pondering that I tried another hunch and made one more round of
changes, namely I re-added @RequestScoped to my PersonBean and changed
@Stateless to @Stateful then in my ReST resource I changed the @EJB
annotation back to @Inject et voila it work this way as well.

Now that said, does this mean that because I used an EJB annotation
(to trigger the Container Managed EM) that this class can not act as a
CDI ManagedBean? I ask this based on the Java EE 6 Tutorial section on
Managed Beans in Part V Contexts and Dependency Injection which says
"A top-level Java class is a managed bean if it is defined to be a
managed bean by any other Java EE technology specification (for
example, the JavaServer Faces technology specification), or if it
meets all of the following conditions:

....
* It is not annotated with an EJB component-defining annotation or
declared as an EJB bean in ejb-jar.xml
...

Or is it a CDI ManagedBean because I have the class annotated with
@RequestScoped even though it is also annotated with @Stateful ?

Thanks,

-Noah