EJB

If you ever created an EJB application using older versions of JEE specifications, J2EE, you would remember that data persistence was achieved using Entity Beans, which implemented the javax.ejb.EntityBean interface, and you had to implement all those horrifying methods and provide different implementations, depending on the persistence nature of the entity bean, that is container-managed or bean-managed.

Thanks, mostly, to Hibernate, the Java Persistence API (JPA) was born to simplify the implementation. In the next section, we will see how to set up Hibernate as the entity manager when using EJB 3.

Persistence unit

In the JPA world, the Entity Manager represents the persistence unit. It is defined by the javax.persistence.EntityManager interface. This is the JPA API that is your gateway to the persistence store, just as the Hibernate Session is when working directly through the Hibernate API. In EJB3, you will need to declare the persistence unit and let the application server know who the provider is if you wish to override the provided implementation.

The persistence unit is declared in a file called persistence.xml, located in the META-INF directory. Here is a sample that tells the EJB container to use Hibernate as the JPA provider. It also tells the container that you wish to use JTA for transaction management. Let's check the following example:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
  xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
  http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="MasteringHibernate"
    transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:jboss/datasources/postgresDS</jta-data-source>

    <class>com.packt.hibernate.ch9.model.Person</class>
    <class>com.packt.hibernate.ch9.model.Child</class>

    <properties>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
      <property name="hibernate.hbm2ddl.auto" value="update" />
      <property name="hibernate.show_sql" value="true" />
      <property name="hibernate.format_sql" value="true" />
    </properties>
  </persistence-unit>
</persistence>

This is also where you declare the entity classes. As can be seen, you can include in-container, provider-specific properties—in this case, the Hibernate dialect and other properties.

Server resources

As we saw in the previous section, the only resource that needs to be configured in the persistence unit is the JTA data source. But, behind the scenes, your application server has to provide the JDBC driver, create a connection factory, and manage transactions, and all of that requires configuration and management on the server side. However, such tasks are beyond the scope of this book as they are specific to each application server.

For the sake of demonstration, we will briefly discuss these steps here using JBoss AS 7 and PostgreSQL as the database.

You can specify the connection information, set up the database driver, and configure a connection pool in your JBoss configuration file, as shown in the following code snippet.

Tip

If you are using the simple standalone version of JBoss, this configuration file is called standalone.xml and is located in the directory called /standalone/configuration, under the JBoss directory.

Note that the data source is registered as a JNDI resource, which is used by the persistence unit we saw earlier:

<datasource jta="true" jndi-name="java:jboss/datasources/postgresDS" 
        pool-name="postgresDS" enabled="true" use-java-context="true" use-ccm="false">
        <connection-url>jdbc:postgresql://localhost:5432/packtdb</connection-url>
        <driver-class>org.postgresql.Driver</driver-class>
        <driver>postgresqlDriver</driver>
        <pool>
            <min-pool-size>5</min-pool-size>
            <max-pool-size>100</max-pool-size>
            <prefill>true</prefill>
        </pool>
        <security>
            <user-name>dbUser</user-name>
            <password>password</password>
        </security>
    </datasource>
    <drivers>
        <driver name="postgresqlDriver" module="org.postgresql">
            <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
        </driver>
    </drivers>
</datasources>

Furthermore, note that this data source is set up as a JTA resource and the driver class used for this data source is the XA flavor. Finally, the module that contains the PostgreSQL drivers is called org.postgresql, as shown in the earlier example.

Note

JBoss uses modules to extend its capabilities. In fact, Hibernate is added as a module. So, if you need to upgrade Hibernate, look for its module and upgrade the JARs there. Refer to the JBoss documents for more information.

To add your database driver to JBoss as a module, create a directory under the JBoss module's directory, copy the JARs to the new directory,, and create a file called module.xml to tell JBoss about the new module. The name of the module directory is very important. Since the module is called org.postgresql, the directory must be called org/postgresql/main. The contents of this directory are shown here:

$ pwd
/opt/jboss-as-7.1.1/modules/org/postgresql/main

$ ls
module.xmlpostgresql-9.4.jar		postgresql-9.4.jar.index

$ cat module.xml 
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.postgresql">
    <resources>
        <resource-root path="postgresql-9.4.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>

The index file is created by JBoss; after you restart it, it will discover this new module and create an index file.

Now, you are ready to start using Hibernate.

Entity manager

In this section, we will discuss how to work with the entity manager in a session bean. So far, we have been working with Hibernate sessions, and most of the examples used to demonstrate the concept were for a standalone application.

But when you use Hibernate in an EJB context, things are a little different. First, let's recognize the choice that you have between using the JPA interface, that is the entity manager, and the Hibernate interface, that is a session. Throughout this book, we have mostly covered Hibernate sessions. But, for now, we will focus mostly on the entity manager.

When you declare your persistence unit, as shown earlier, you can simply inject it in your session bean, using the annotation @PersistenceContext. Consider the following example:

@Stateless(name="personBean")
public class PersonBean implements PersonDAO {	
  @PersistenceContext(unitName = "MasteringHibernate")
  private EntityManager entityManager;
  
  @Override
  public Person findById(long id) {
    return entityManager.find(Person.class, id);
  }
  @Override
  public List<Person> findAll() {
    List<Person> persons = 
            entityManager.createQuery("from Person", Person.class)
            .getResultList();
    return persons;
  }

  @Override
  public void save(Person person) {
    entityManager.persist(person);
  }

  @Override
  public void update(Person person) {
    entityManager.merge(person);
  }

  @Override
  public void delete(long id) {
    Person person = entityManager.find(Person.class, id);
    if (person == null) {
      throw new RuntimeException("Object not found!");
    }
    for(Child child: person.getChildren()) {
      delete(child);
    }
    delete(person);
  }

  @Override
  public void delete(Object entity) {
    entityManager.remove(entity);
  }
}

The first thing to notice is the auto-wired persistence context. Once you declare your persistence unit in the persistence.xml file, you can inject it in your EJBs (a stateful/stateless session and a message-driven bean), as shown in the preceding example.

Note

You can also look up the persistence unit, using a JNDI context lookup. But, when working with EJBs, there is no need to do that; just use an annotation.

The rest of the example comprises simple data access methods using the entity manager API. There seems to be something missing! What about a transaction? Let's discuss that next.

Transaction

In the example shown in the previous section, we didn't declare any transactional attributes or demarcate a transaction. There are two reasons for this. First, by default, the EJB container manages transactions for the beans. Second, every EJB method, by default, requires a transaction. So, if you don't provide any transactional attribute, the container will create a transaction before invoking the EJB method, if one doesn't already exist. By default, transactions propagate across different methods in the same execution path.

You can specify different transaction attributes per EJB specifications. For example, if an EJB method should run in its own transaction, you can annotate the method using @TransactionAttributeType.REQUIRES_NEW to suspend the current transaction and start a new one.

The scope of the entity manager is set to the transaction. This means that, once the transaction commits, the entity manager is flushed and closed.

If the EJB, and not the container, manages your transaction, you are responsible for starting and committing the transaction in your EJB method. For further information on this, refer to the Java enterprise documentation, as EJBs are beyond the scope of this book.

Hibernate session

When working with EJBs while using Hibernate as the JPA implementation, you can still access the Hibernate Session. Throughout this book, we have already pointed out a few things you can do with Hibernate Session that are not offered through JPA interface. So, there might be scenarios under which you would need to access the Session object.

You can access the underlying session by asking the entity manager to provide the underlying implementation. For example, you can replace the find method, shown in the earlier example, to use the Hibernate session. The Hibernate session is obtained by calling the unwrap method on the entity manager API:

@Override
public Person findById(long id) {
  Session session = entityManager.unwrap(Session.class);
  return (Person) session.get(Person.class, id);
}

If you use JBoss, you can in fact use the Hibernate session as your entity manager.

public class PersonBean implements PersonDAO {	
  @PersistenceContext(unitName = "MasteringHibernate")
  private Session session;
  …
}

Clearly, this will not work in EJB containers other than JBoss.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.176.88