Home  >  Development  >  features

Anatomy of an Enterprise Flex RIA Part 10: DTOs or VOs

| | Comments (2)
AddThis Social Bookmark Button
 
riaseries_part10.jpg

Last installment we looked at the Actionscript and Java code for the persistent entities in our application. This week we'll look at the code that will create, update, and delete those entities: the service layer.

DTOs or VOs

The traditional enterprise pattern that addresses this task of transferring objects full of data from one system to another is the Data Transfer Object (DTO; sometimes called the Value Object, or VO). Often, weightier code than we’ll need was used to get the data needed in an object out of the database and into a lightweight object, the DTO, and then that object was transferred across the wire and used as needed. In this case, EJB 3.0 does all the work of getting the data into and out of the database for us. The entities fulfill the role of defining the mapping to the database tables and holding the data for transfer and manipulation.

Note that most of the Cairngorm projects you’ll see use VO instead of DTO, although most of the enterprise Java world has standardized on DTO. They mean the same thing.

Session Beans

Along with entity beans, session beans are a type of class that EJB 3.0 specifies for providing services and managing business processes. Of course, central to these processes are entities that are important to the business logic. Session beans come in two flavors: stateful and stateless. Stateful session beans have a concept of a session which spans multiple requests and keeps a “conversational state” from one request to another. A conversational state is simply all the important information about a client’s interactions with the bean over the lifespan of the bean. The EJB container, such as JBoss, keeps the bean ready for the next call from its previous client.

Our sample application, like most, if not all, RIAs, has no need for the beans to keep track of a user’s state. State is generally kept on the client with RIAs, because the client stays in memory and isn’t limited by the request-response cycle, as a simple web page is. Our sessions will be conducted one call at a time through the other type of session bean, the stateless bean, which is the same as a stateful bean but without keeping any state. The stateful beans will act as Data Access Objects (DAOs) for our entities. That just means they’ll get the objects into and out of the database, and they’ll be responsible for any business logic at those points.

Here’s the syntax for creating a stateless session bean:

@Stateless
@Local(value={BookDAO.class})
public class BookDAOBean implements BookDAO {
 …

Just like @Entity does for an entity bean, @Stateless and its counterpart, @Stateful, mark a class as a session bean. One other requirement, though, is that the bean implements an interface that lets the container know which methods should be exposed to different requests. These requests could be local or remote, because beans can be distributed across different servers. The beans can have more than one interface to mark which methods are available to the different types of requests. We’ll only need to expose local access, so we’ll tell the container which class the local interface is with an @Local annotation. Here’s a look at that interface:

package lcds.examples.bookie.dao;
...
public interface BookDAO {
     public void persist(Book transientInstance);
     public void remove(Book persistentInstance);
     public Book merge(Book detachedInstance);
     public Book findById(int id);
     public List<Book> getAll();
     public List<Book> findByAuthor(Person author);
     public List<Book> findBySubject(Subject subject);
     public Collection<Book> findByName(String title);
     public void removeDetached(Book detachedInstance);
}

These are all the things our code can do to a book or collection of books.

Here’s more of the code for the book session bean:

package lcds.examples.bookie.dao.beans;
&#133;
@Stateless
@Local(value={BookDAO.class})
public class BookDAOBean implements BookDAO {
 
     @PersistenceContext
     private EntityManager entityManager;
 
     public void persist(Book transientInstance) {
           try {
                 entityManager.persist(transientInstance);
            } catch (RuntimeException re) {
                 throw re;
            }
      }
 
     public void remove(Book persistentInstance) {
           try {
                 entityManager.remove(persistentInstance);
            } catch (RuntimeException re) {
                 throw re;
            }
      }

These two methods—persist and remove—take an instance of a book. persist should be called for entities that don’t yet exist in the database, and remove will end up removing an entity from the database. These methods call methods of the same name on an object of type EntityManager. Notice, though, that that object is never instantiated. It is, however, marked with an @PersistenceContext annotation. This is part of what being a session bean is about in EJB 3.0. The EntityManager is instantiated at runtime and the container gives the session bean the instance that matches the persistence context in which the bean is running. If there is more than one instance, the annotation can specify which one it wants, but in our example, the persistence context is just the one persistence unit, so all the beans in our persistence unit get the same entity manager.

This process—in which the container gives our object the right instance of an object it needs—is called dependency injection. The entity manager is injected into our session bean at runtime. The container instantiates the manager in the right way so that we don’t have to know how to do it in our code, because there may be many things we just won’t know while we’re writing the code. Let’s look at a few more methods to see the types of operations the rest of our beans will perform on their respective entities:

    public Book merge(Book detachedInstance) {
          try {
                Book result = 
                     entityManager.merge(detachedInstance);
                return result;
           } catch (RuntimeException re) {
                     throw re;
           }
     }

    public void removeDetached(Book detachedInstance) {
          remove(merge(detachedInstance));
     }

persist and remove basically map to SQL’s insert and delete statements. merge fulfills two use cases. The first case maps directly onto the SQL update statement; merge will take the changes from an entity and queue them for update into the database. EJB has a concept of entities which are managed by an EntityManager, however. What really happens when the entity manager’s remove is called is that the entity is removed from being managed by the manager, which queues it for removal from the database. The object may still exist, though, because code may have a reference to it. It’s possible to put the object right back into the manager by saying merge.

This case illustrates the difference between a detached entity and a managed entity. So, what’s the difference between calling persist and merge with a detached entity? Nothing, really; either way, the object will be inserted if it doesn’t exist. persist will have a problem if the entity already existed in database form, though, whereas merge will not.

Because we’ll often be sending objects from the client side that may not have been pulled out of the database into the entity manager, we’ll pretty much always call merge for both new objects and updates to existing ones, just to be safe. This explains why I have the removeDetached method as well: sometimes we may want to delete an object that hasn’t been loaded into the entity manager yet, and we won’t know unless we make the process more complicated. If we try to remove a detached entity, the entity manager complains that it doesn’t know anything about this object. In this case, it’s easier to merge the object first to make sure it’s managed by the entity manager, and then to remove it.

    public Book findById(int id) {
          try {
                Book instance = entityManager.find(Book.class, id);
                return instance;
           } catch (RuntimeException re) {
                throw re;
           }
     }
    
    public List<Book> getAll() {
          Query q = entityManager.createQuery(
                    "from Book b" +
                    " order by b.title"
               );
               List<Book> results = q.getResultList();
                return results;
     }

    public List<Book> findByAuthor(Person author) {
          Query q = entityManager.createQuery(
               "from Book b" +
               " where b.author.id = :author_id"
          );
          q.setParameter("author_id", author.getId());
          List<Book> results = q.getResultList();
          return results;
     }
    

In the preceding code, I included a few more methods as examples of what we’ll do with session beans. findById calls the entity manager’s find(Class, int) method. It looks at the class to see where it’s mapped, and then it does a select to find the row that matches the ID. Simple.

getAll introduces us to a query. Queries are created from the entity manager. A standard query in EJB uses EJBQL, instead of SQL. EJBQL looks an awful lot like SQL, but it allows you to refer to classes instead of tables, and properties instead of columns. The results fit easily into a list.

findByAuthor shows another feature of a query in EJB 3.0. Just like SQL, EJBQL has a where clause. Notice that the syntax lets us specify a named parameter in the form : <param name>. On the line after we create the query, we call the setParameter method to get the author’s ID into that parameter, so the query will find all books that have a certain author ID.

Figure 13 shows the rest of the session beans in the data project.

anatomy10_fig13.jpg
Figure 13. The rest of the session beans in the data project

Next installment we're going to look at testing the Java part of our application using TestNG. You can always find the entire series here.

Comments

2 Comments

Panna said:

Hello Tony,
I've purchased your book and I'm stumbling while running the
sample application.
Maven can't build 4 artifacts.
It's the same problem as Martin had.
I've looked on the repo site manually but can't find them.
It would be nice if you could help me out.

Kind regards.

@Panna - did you make sure to extract the maven repository file (http://examples.oreilly.com/9780596514402/m2_repository.zip) into the .m2 directory in your home directory?

Leave a comment


Type the characters you see in the picture above.

Related Books

Development Series

Get an overview of the tools and technologies that work together to allow developers to build Rich Internet Applications (RIAs) quickly and easily.

Anatomy of an Enterprise Flex RIA

Archives


 
 


Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.

About Us
Meet the Experts
Meet Our Contributors
Send Us Feedback