For better performance, wrap the entity bean in a session bean facade. The performance benefits of a session facade are fewer remote method calls and an outer transaction context with which each getter method invocation does not start a new transaction. Session facade is one of the core Java EE design patterns (http://www.oracle.com/technetwork/java/sessionfacade-141285.html). To create a session bean, go to File | New | Other and select EJB|Session Bean (EJB 3.X) and click on Next as shown in the following screenshot:
Select the EJB project in which you want to create a session bean. The Source folder and package are the same as the folder for the entity classes. Specify Class name as CatalogSessionBeanFacade
. Select the session bean State type as Stateless, which does not incur the overhead of keeping the state of the session bean. Select Remote for the Create business interface option and specify the remote class name as CatalogSessionBeanFacadeRemote. Now, click on Next as shown in the following screenshot:
Specify Mapped name as EJB3-SessionEJB, Transaction Type as Container. The mapped name is used to look up the session bean from a client. Now, click on Finish as shown in the following screenshot:
A session bean class and the remote business interface get created. The session bean class is annotated with the @Stateless
annotation with name and mappedName
elements.
@Stateless(name="CatalogSessionBean", mappedName="EJB3-SessionEJB") public class CatalogSessionBeanFacade implements CatalogSessionBeanFacadeRemote { }
Next, we will modify the default session bean generated by the session bean wizard.
An EntityManager
is used
to create, remove, find, and query persistence entity instances. Inject an EntityManager
, using the @PersistenceContext
annotation. Specify the unitName
as the unitName
configured in persistence.xml
.
@PersistenceContext(unitName = "em") EntityManager em;
In this section, we shall specify
getter methods for Collections
of entities. For example, the getAllEditions
method gets all Edition
entities using the named query findEditionAll
. The createNamedQuery
method of EntityManager
is used to create a Query
object from a named query. Specify the TransactionAttribute
annotation's TransactionAttributeType
enum to REQUIRES_NEW
, with which the EJB container invokes a session bean method with a new transaction context. REQUIRES_NEW
has the advantage that if a transaction is rolled back due to an error in a different transaction context from which the session bean is invoked it does not effect the session bean that has the TransactionAttributeType
set to REQUIRES_NEW
.
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public List<Edition> getAllEditions() { ArrayList<Edition> editions = new ArrayList<Edition>(); Query q = em.createNamedQuery("findEditionAll"); for (Object ed : q.getResultList()) { editions.add((Edition)ed); } return editions; }
As we have EJB
relationships between different entities, making modifications such as updating or deleting data would affect the associated entities. To demonstrate the use of the entities, we shall create some test data and subsequently delete the data. Create test data with the createTestData
convenience method in the session bean. Alternatively, a unit test or an extension class may also be used. Create a Catalog
entity and set the journal using the setJournal
method. Persist the entity using the persist
method of the EntityManager
object and synchronize the entity with the database using the flush
method.
Catalog catalog1 = new Catalog(); catalog1.setId(1); catalog1.setJournal("Oracle Magazine"); em.persist(catalog1); em.flush();
Similarly, we can use the create, persist, and flush methods in an Edition
entity object. Before adding the Edition
object to the database merge the Catalog
entity with the persistence context using the merge
method.
Edition edition = new Edition(); edition.setEdition("January/February 2009"); em.persist(edition); em.flush(); em.merge(catalog1); catalog1.addEdition(edition);
Similarly,
add the Section
and Article
entity instances. Delete some data with the deleteSomeData
method in which we shall create a Query
object using the named query findArticleByTitle
. Specify the article title using the setParameter
method of the Query
object. Get the result List
using the getResultList
method of the Query
object. Iterate over the result List
and remove the article using the remove
method of the EntityManager
object.
public void deleteSomeData() { // remove an article Query q = em.createNamedQuery("findArticleByTitle"); q.setParameter("title", "Launching Performance"); List list = q.getResultList(); for (Object article : list) { em.remove(article); } }
Also, add remove<>
methods to remove entities.
The session bean class is listed as follows:
package ejb3; import javax.ejb.*; import javax.persistence.*; import java.util.*;
Annotate the session bean with the @Stateless
annotation, which
includes the mappedName
used to look up the session bean from a client:
@Stateless(name = "CatalogSessionBean", mappedName = "EJB3-SessionEJB") public class CatalogSessionBeanFacade implements CatalogSessionBeanFacadeRemote { @PersistenceContext(unitName = "em") EntityManager em;
Specify the getter collections methods for the different entities:
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public List<Edition> getAllEditions() { ArrayList<Edition> editions = new ArrayList<Edition>(); Query q = em.createNamedQuery("findEditionAll"); for (Object ed : q.getResultList()) { editions.add((Edition) ed); } return editions; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public List<Section> getAllSections() { ArrayList<Section> sections = new ArrayList<Section>(); Query q = em.createNamedQuery("findSectionAll"); for (Object ed : q.getResultList()) { sections.add((Section) ed); } return sections; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public List<Article> getAllArticles() { ArrayList<Article> articles = new ArrayList<Article>(); Query q = em.createNamedQuery("findArticleAll"); for (Object ed : q.getResultList()) { articles.add((Article) ed); } return articles; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public List<Catalog> getAllCatalogs() { Query q = em.createNamedQuery("findCatalogAll"); List<Catalog> catalogs = q.getResultList(); ArrayList<Catalog> catalogList = new ArrayList<Catalog>(catalogs.size()); for (Catalog catalog : catalogs) { catalogList.add(catalog); } return catalogList; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public List<Edition> getCatalogEditions(Catalog catalog) { em.merge(catalog); List<Edition> editions = catalog.getEditions(); ArrayList<Edition> editionList = new ArrayList<Edition>(editions.size()); for (Edition edition : editions) { editionList.add(edition); } return editionList; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public List<Section> getEditionSections(Edition edition) { em.merge(edition); List<Section> sections = edition.getSections(); ArrayList<Section> sectionList = new ArrayList<Section>(sections.size()); for (Section section : sections) { sectionList.add(section); } return sectionList; } @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) public List<Article> getSectionArticles(Section section) { em.merge(section); List<Article> articles = section.getArticles(); ArrayList<Article> articleList = new ArrayList<Article>(articles.size()); for (Article article : articles) { articleList.add(article); } return articleList; }
Add a convenience method to create test data.
public void createTestData() { // create catalog for Oracle Magazine Catalog catalog1 = new Catalog(); // catalog1.setId(1); catalog1.setJournal("Oracle Magazine"); em.persist(catalog1); em.flush(); // Add an Edition Edition edition = new Edition(); // edition.setId(2); edition.setEdition("January/February 2009"); em.persist(edition); // em.refresh(edition); em.flush(); em.merge(catalog1); catalog1.addEdition(edition); // Add a Features Section Section features = new Section(); // features.setId(31); features.setSectionname("FEATURES"); em.persist(features); em.merge(edition); edition.addSection(features); // add an article to Features section Article article = new Article(); // article.setId(41); article.setTitle("Launching Performance"); article.setSection(features); em.persist(article); em.merge(features); features.addArticle(article); em.flush(); // add a Technology section Section technology = new Section(); // technology.setId(32); technology.setSectionname("Technology"); em.persist(technology); em.merge(edition); edition.addSection(technology); // add an article to Technology section article = new Article(); // article.setId(42); article.setSection(technology); article.setTitle("On Dynamic Sampling"); em.persist(article); em.merge(technology); technology.addArticle(article); em.flush(); }
Add another convenience method to delete some data.
public void deleteSomeData() { // remove an article Query q = em.createNamedQuery("findArticleByTitle"); q.setParameter("title", "Launching Performance"); List list = q.getResultList(); for (Object article : list) { em.remove(article); } }
Add some remove<Entity>
methods to remove entities:
public void removeEdition(Edition edition) { Catalog catalog = edition.getCatalog(); catalog.removeEdition(edition); em.remove(edition); } public void removeSection(Section section) { Edition edition = section.getEdition(); edition.removeSection(section); em.remove(section); } public void removeArticle(Article article) { Section section = article.getSection(); section.removeArticle(article); em.remove(article); } }
The remote business interface is listed as follows:
package ejb3; import javax.ejb.*; import java.util.*; @Remote public interface CatalogSessionBeanFacadeRemote { public List<Edition> getAllEditions(); public List<Section> getAllSections(); public List<Article> getAllArticles(); public List<Catalog> getAllCatalogs(); public List<Edition> getCatalogEditions(Catalog catalog); public List<Section> getEditionSections(Edition edition); public List<Article> getSectionArticles(Section section); public void createTestData(); public void deleteSomeData(); public void removeEdition(Edition edition); public void removeSection(Section section); public void removeArticle(Article article); }