2 Replies Latest reply: Jul 11, 2008 7:38 PM by 843833 RSS

    Using the Model Facade Pattern in a Java EE 5 Web application

    843833
      Hi,

      Yutaka and I did a Tech tip
      http://java.sun.com/mailers/techtips/enterprise/2006/TechTips_Nov06.html#2 on using a model facade pattern in Java EE 5 web-only applications recently. We got some questions about it, and these were some of the questions raised...

      Question 1) the first part of the tech tip(it has two articles in it) http://java.sun.com/mailers/techtips/enterprise/2006/TechTips_Nov06.html showed how to access Java Persistence objects directly from a JSF managed bean, is this a good practice?

      Question 2) when to use a facade(as mentioned in the second part of tech tip) ?

      and maybe
      Question 3) why doesn't the platform make this easier and provide the facade for you?

      Briefly, I will take a shot at answering these three questions

      Answer 1) You can access Java persistence directly from your managed beans, but as your application grows and you start to add more JSF managed beans or other web components(servlets, JSP pages etc) that also directly access Java Persistence objects, you will start to see that you are cutting/pasting similiar code to handle the transactions and to handle the Java Persistence EntityManager and other APIs in many places. So for larger applications, it is a good practice to introduce a model facade to centralize code and encapsulate teh details of the domain model management

      Answer 2) IAs mentioned in answer 1, its good to use a model facade when your application starts to grow. For simple cases a spearate model facade class may not be needed and having managed beans do some of the work is a fast way to jumpstart you application development. But a facade can help keep the code clean and easier to maintain as the aplication grows.

      Answer 3) First note that both of the articles in the tech tip were about pure web apps(not using any EJBs) and running on the Java EE5 platform. Yes it would be nice if a facility like this was made available for web-only applications(those not using EJBs). But for web-only applications you will need to use a hand-rolled facade as we outlined in the tech tip. The Java EE platform does provide a way to make implementing a facde easier though, and the solution for that is to use a Session Bean. This solution does require that you use ythe EJB container and have a Session Bean facade to access your Java Persistence objects and manage the transactions. The EJB Session Facade can do a lot of the work for you and you dont have to write code to manage the transactions or manage the EntityManager. This solution was not covered in this tech tip article but is covered in the Java BluePrints Solutions Catalog for Perssitence at
      https://blueprints.dev.java.net/bpcatalog/ee5/persistence/facade.html in the section "Strategy 2: Using a Session Bean Facade" . Maybe we can cover that in a future tech tip.

      Please ask anymore questions about the tech tip topic on this forum and we will try to answer.

      hth,
      Sean
        • 1. Re: Using the Model Facade Pattern in a Java EE 5 Web application
          843833
          Hi,

          Also, I just wanted to mention ... in answer number 2 ... that managed beans can also use a facade pattern. So if the appliocation in tech tip part 1 started to grow in complexity, you could move all the pesrsistence code (code that does the persistence access and calls to the entitymanager and all the transaction code) and move it to a new facade class.
          What would the code in tech tip part 1 look like if it was refactored to use a model facade?

          The the code in the managed bean "public class UserNumberBean" in the code example in would be simplified so that the methods just called the session facade methods and the persistence code could be moved from the managedbean and into new methods on the facade.

          In other words, you could move all the persitence code into a facade class and out of the managed bean so that you encapsulate all the model tier code behind the facade.

          I guess the point I am trying to make is that you can also use the model facade pattern with JSF applications.

          hth,
          Sean
          • 2. Re: Using the Model Facade Pattern in a Java EE 5 Web application
            843833
            Hi Sean,

            I'm working on an implementation of the Model Facade pattern where you can possibly have many facades designed as services. Each service extends a basic POJO class which I'm calling CRUDService: its short code is provided below for your convenience.

            The CRUDService class is meant to generalize CRUD operations regardless of the type of the object being used. So the service can be called as follows, for example:
            Job flightAtt = new Job();
            ...
            SERVICE.create(flightAtt);
            ...
            Runway r = (Runway) SERVICE.read(Runway.class, 2);
            ...
            Employee e = (Employee) SERVICE.read(Employee.class, 4);
            ...
            SERVICE.update(e);
            ...
            SERVICE.delete(r);
            SERVICE is a Singleton, the only instance of some service class extending CRUDService. Such a class will always include other methods encapsulating named queries, so the client won't need to know anything about the persistence layer.

            Please notice that, in this scenario, DAOs aren't needed anymore as their role is now distributed among CRUDService and its subclasses.

            My questions, then:

            . Do you see any obvious pitfalls in what I've just described?

            . Do you think traditional DAOs should still be used under JPA?

            . It seems to me the Model Facade pattern isn't widely used because such a role can be fulfilled by frameworks like Spring... Would you agree?

            Thanks so much,

            Cristina Belderrain
            Sao Paulo, Brazil

            public class CRUDService {
                
                protected static final Logger LOGGER = Logger.
                    getLogger(Logger.GLOBAL_LOGGER_NAME);
                protected EntityManager em;
                protected EntityTransaction tx;
            
                private enum TransactionType { CREATE, UPDATE, DELETE };
                
                protected CRUDService(String persistenceUnit) {
                    em = Persistence.createEntityManagerFactory(persistenceUnit).
                        createEntityManager();
                    tx = em.getTransaction();
                }
            
                public boolean create(Object obj) {
                    return execTransaction(obj, TransactionType.CREATE);
                }
            
                public Object read(Class type, Object id) {
                    return em.find(type, id);
                }
                
                public boolean update(Object obj) {
                    return execTransaction(obj, TransactionType.UPDATE);
                }
                
                public boolean delete(Object obj) {
                    return execTransaction(obj, TransactionType.DELETE);
                }
                
                private boolean execTransaction(Object obj, TransactionType txType) {
                    try {
                        tx.begin();
                        if (txType.equals(TransactionType.CREATE))
                            em.persist(obj);
                        else if (txType.equals(TransactionType.UPDATE))
                            em.merge(obj);
                        else if (txType.equals(TransactionType.DELETE))
                            em.remove(obj);
                        tx.commit();
                    } finally {
                        if (tx.isActive()) {
                            LOGGER.severe(txType + " FAILED: ROLLING BACK!");
                            tx.rollback();
                            return false;
                        } else {
                            LOGGER.info(txType + " SUCCESSFUL.");
                            return true;
                        }
                    }
                }
            }