Full WebApplication JSF EJB JPA JAAS – Part 1
In the end of this post you will find the source code to download. You can use it as you wish. Just go to the last page and do the download. \o/
If you downloaded the code and did not understand something, in this post I will explain every detail found in the code. Just read the subject inside this post that you want.
I will list bellow the technologies that I will use in this post:
- JSF 2.0 Mojarra – With ManagedBeans as RequestScope and SessionScope.
- Message Internationalization – File that will have all the messages of our system; it will be easier to translate you pages.
- Default CSS file that will be imported as a library.
- EJB 3 – Our DAOs and Façades will be @Stateless.
- Generic DAO – A generic DAO that will have the CRUD actions to make our life easier.
- JPA 2 – To map our classes in the DB
- JAAS – To control the login and the user access to the pages.
- MVC – I will use this pattern with small modifications.
- Postgres as database, but I will show how to set up your app to MySQL also.
I will not use TDD – JUnit to test our View/Model/Classes, but in the following link you can see a technique to use the JUnit to test your ManagedBeans: JUnit with HSQLDB, JPA and Hibernate.
Tools that we will use:
- Eclipse Indigo – http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/indigor
- I will use JBoss 7 (some readers of this blog asked me for it) – http://download.jboss.org/jbossas/7.0/jboss-as-7.0.2.Final/jboss-as-7.0.2.Final.zip the version is: JBoss 7 Everything (NOT Java EE6 Certified).
- Indigo JBoss Tools (milestone version) – https://www.jboss.org/tools/download/dev.html if you do not know how to install the JBoss Tools in this post I will show how to (User Login Validation with JAAS and JSF). Be aware that in the post I will show how to install to another eclipse version, but the difference is the URL; use this URL instead the URL used in the link above: http://download.jboss.org/jbosstools/updates/development/indigo/
- I will use the Postgres database but you can use any database you want; you will need only to download the database and the JDBC driver. Here you can download the latest Postgres JDBC: http://jdbc.postgresql.org/download.html; the latest version so far is the 4: http://jdbc.postgresql.org/download/postgresql-9.1-901.jdbc4.jar.
This post will have several pages; this first page is just to show the technical details of the post today.
I will not code to interface my model/DAO, just to save space. Remember that you should always code to interfaces (Design Pattern – Strategy).
Before you continue be sure that you installed the JBoss Tools and the JBoss 7 in this exactly order.
Business – Model
Let us create the EJB project that will hold our system business.
Click in the “Finish” button.
Let us create the User and Dog classes that will be inside the “com” package. It will have the code bellow:
package com.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.NamedQuery; import javax.persistence.Table; @Entity @Table(name = 'USERS') @NamedQuery(name='User.findUserByEmail', query='select u from User u where u.email = :email') public class User { public static final String FIND_BY_EMAIL = 'User.findUserByEmail'; @Id @GeneratedValue(strategy=GenerationType.AUTO) private int id; @Column(unique = true) private String email; private String password; private String name; private String role; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } @Override public int hashCode() { return getId(); } @Override public boolean equals(Object obj) { if(obj instanceof User){ User user = (User) obj; return user.getEmail().equals(getEmail()); } return false; } }
package com.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = 'DOGS') public class Dog { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String name; private double weight; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } @Override public int hashCode() { return getId(); } @Override public boolean equals(Object obj) { if(obj instanceof Dog){ Dog dog = (Dog) obj; return dog.getId() == getId(); } return false; } }
About the code above:
- The User class has a field named “role” that will store the role level of the user. I created as a single field and we will leave all data in the same table just to make easier to understand. If you want more details about JAAS you can in this post: User Login Validation with JAAS and JSF.
- I will let the JPA handle the tables Id generations. If you want to change the way of the Id creation you can check this posts to see how to do it: JPA SequenceGenerator, JPA TableGenerator – Simple Primay Key.
- The email will be unique; it will be the login identifier.
- Notice that a class to be declared as Entity, it only needs the following annotations: “@Entity” and “@Id”. The class does not need to implement the Serializable interface.
Business – DAOs
I will use a generic DAO to basic CRUD operations and others two DAOs: one for User and another for Dog. It will be very easy to understand its use:
package com.dao; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.persistence.criteria.CriteriaQuery; public abstract class GenericDAO<T> { private final static String UNIT_NAME = 'CrudPU'; @PersistenceContext(unitName = UNIT_NAME) private EntityManager em; private Class<T> entityClass; public GenericDAO(Class<T> entityClass) { this.entityClass = entityClass; } public void save(T entity) { em.persist(entity); } public void delete(T entity) { T entityToBeRemoved = em.merge(entity); em.remove(entityToBeRemoved); } public T update(T entity) { return em.merge(entity); } public T find(int entityID) { return em.find(entityClass, entityID); } // Using the unchecked because JPA does not have a // em.getCriteriaBuilder().createQuery()<T> method @SuppressWarnings({ 'unchecked', 'rawtypes' }) public List<T> findAll() { CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); cq.select(cq.from(entityClass)); return em.createQuery(cq).getResultList(); } // Using the unchecked because JPA does not have a // ery.getSingleResult()<T> method @SuppressWarnings('unchecked') protected T findOneResult(String namedQuery, Map<String, Object> parameters) { T result = null; try { Query query = em.createNamedQuery(namedQuery); // Method that will populate parameters if they are passed not null and empty if (parameters != null && !parameters.isEmpty()) { populateQueryParameters(query, parameters); } result = (T) query.getSingleResult(); } catch (Exception e) { System.out.println('Error while running query: ' + e.getMessage()); e.printStackTrace(); } return result; } private void populateQueryParameters(Query query, Map<String, Object> parameters) { for (Entry<String, Object> entry : parameters.entrySet()) { query.setParameter(entry.getKey(), entry.getValue()); } } }
package com.dao; import javax.ejb.Stateless; import com.model.Dog; @Stateless public class DogDAO extends GenericDAO<Dog> { public DogDAO() { super(Dog.class); } }
package com.dao; import java.util.HashMap; import java.util.Map; import javax.ejb.Stateless; import com.model.User; @Stateless public class UserDAO extends GenericDAO<User> { public UserDAO() { super(User.class); } public User findUserByEmail(String email){ Map<String, Object> parameters = new HashMap<String, Object>(); parameters.put('email', email); return super.findOneResult(User.FIND_BY_EMAIL, parameters); } }
About the code above:
- I hid some warnings because the JPA code does not “understand” generics yet.
- The method “findOneResult” is with protected access just to prevent external access from other classes; this method requires logic to populate the parameters as we can see in the UserDAO.
- The class GenericDAO has a complete CRUD methods plus a method that returns a single object given a NamedQuery.
- The UserDAO class has a method (findUserByEmail) that belongs only to the class; but it has all CRUD methods by inheritance. With this pattern of DAOs we got a code more flexible.
- The DogDAO has no method in it but only the CRUD methods; you could implement any method in the class without problem.
- Instead using a method to “save” and other to “update” your objects you could use one method “entityManager.merge()”. You will have the same result but you will need to pay attention to the Cascade options.
- I did not use Interfaces because EJB 3.1 allows us to have Stateless Local Session Beans without interface. If you are using an older EJB version you will need to implement an interface (how to Implement EJBs with interfaces we will see in this post, in the Façades page). I will not develop with interfaces my DAO/Model just to save space in this post. Remember: “Always program to an interface” (Design Pattern – Strategy).
- If you use the JBoss 4.2 you could use the org.jboss.annotation.ejb.LocalBinding or org.jboss.annotation.ejb.RemoteBinding annotations; in this annotation you can write the name that will be mapped and referred by the EJB.
Business – Façades
I will create Façades that will be the “bridge” between the View and the DAO. In the Façade we will leave all the business rules leaving the DAO only the “database” functions/transactions, e.g. CRUD and queries.
Let us see how our class UserFacade and DogFacade will be:
package com.facade; import java.util.List; import javax.ejb.Local; import com.model.Dog; @Local public interface DogFacade { public abstract void save(Dog dog); public abstract Dog update(Dog dog); public abstract void delete(Dog dog); public abstract Dog find(int entityID); public abstract List<Dog> findAll(); }
package com.facade; import java.util.List; import javax.ejb.EJB; import javax.ejb.Stateless; import com.dao.DogDAO; import com.model.Dog; @Stateless public class DogFacadeImp implements DogFacade { @EJB private DogDAO dogDAO; @Override public void save(Dog dog) { isDogWithAllData(dog); dogDAO.save(dog); } @Override public Dog update(Dog dog) { isDogWithAllData(dog); return dogDAO.update(dog); } @Override public void delete(Dog dog) { dogDAO.delete(dog); } @Override public Dog find(int entityID) { return dogDAO.find(entityID); } @Override public List<Dog> findAll() { return dogDAO.findAll(); } private void isDogWithAllData(Dog dog){ boolean hasError = false; if(dog == null){ hasError = true; } if (dog.getName() == null || ''.equals(dog.getName().trim())){ hasError = true; } if(dog.getWeight() <= 0){ hasError = true; } if (hasError){ throw new IllegalArgumentException('The dog is missing data. Check the name and weight, they should have value.'); } } }
package com.facade; import javax.ejb.Local; import com.model.User; @Local public interface UserFacade { public User findUserByEmail(String email); }
package com.facade; import javax.ejb.EJB; import javax.ejb.Stateless; import com.dao.UserDAO; import com.model.User; @Stateless public class UserFacadeImp implements UserFacade { @EJB private UserDAO userDAO; public User findUserByEmail(String email) { return userDAO.findUserByEmail(email); } }
About the code above:
- The DogFacadeImp class does all the work of protecting the DogDAO from the view. It might have the business rules and avoid access to the database if some data is missing or any other business rule has being broken.
- The UserFacade has only one method because we will not have a User crud in this post; the bean will only search for a User if the view does not find it in the HttpSession.
- If you use the JBoss 4.2 you could use the org.jboss.annotation.ejb.LocalBinding or org.jboss.annotation.ejb.RemoteBinding annotations; in this annotation you can write the name that will be mapped and referred by the EJB.
- I do a validation in the DogFacadeImp to be sure that the Dog has only valid data. Remember that everyone can send you invalid data and your view validation may not work as you expect. The data of your application is very important and a double check is always worth.
The interfaces are annotated with the @Local but I remember you that this annotation is optional. If you do no write the @Local annotation your server will assume that your EJB is local by default.
Business – Datasource (by module)
We also need to setup our datasource.
At first I tried to create a datasource by following this tutorial http://community.jboss.org/wiki/JBossAS7-DatasourceConfigurationForPostgresql (I do follow tutorials just like any other human being does), but several errors started to happen after deploy with EJBs and the JBoss could not locate the Postgres jar.
If you are using the JBoss 6 or any version under it you do not need to create the module; just put the file in the “default/lib” folder. If you have any doubt about set up a datasource, I show how to do it, in the JBoss 6 or other version under it, here: User Login Validation with JAAS and JSF.
Let us create the Postgres module. Inside your JBoss 7 create the directory: “YOUR_JBOSS/modules/org/postgresql/main”. Copy the jar to the created directory and create a file named “module.xml”; copy the code bellow inside the “module.xml” file:
<?xml version='1.0' encoding='UTF-8'?> <module xmlns='urn:jboss:module:1.0' name='org.postgresql'> <resources> <resource-root path='postgresql-9.1-901.jdbc4.jar'/> </resources> <dependencies><module name='javax.api'/></dependencies> </module>
Notice that inside the “module.xml” file we have the jar file name written, the name must be the same of the Postgres jar file name.
To create the MySQL module create the following folder “YOUR_JBOSS/modules/com/mysql/main”. Copy the jar to the created directory and create a file named “module.xml”; copy the code bellow inside the “module.xml” file:
<?xml version='1.0' encoding='UTF-8'?> <!-- ~ JBoss copyrights ~ http://community.jboss.org/wiki/DataSourceConfigurationInAS7 --> <module xmlns='urn:jboss:module:1.0' name='com.mysql'> <resources> <resource-root path='mysql-connector-java-5.1.15.jar'/> </resources> <dependencies> <module name='javax.api'/> </dependencies> </module>
Let us edit the file “YOUR_JBOSS/standalone/configuration/standalone.xml”. Inside the key “<datasources>” add the code bellow:
<datasources> <!-- Add this config: begin --> <datasource jndi-name='CrudDS' pool-name='CrudDS_Pool' enabled='true' jta='true' use-java-context='true' use-ccm='true'> <connection-url>jdbc:postgresql://localhost:5432/CrudDB</connection-url> <driver-class>org.postgresql.Driver</driver-class> <driver>postgresql-jdbc4</driver> <pool> <min-pool-size>2</min-pool-size> <max-pool-size>20</max-pool-size> <prefill>true</prefill> <use-strict-min>false</use-strict-min> <flush-strategy>FailingConnectionOnly</flush-strategy> </pool> <security> <user-name>postgres</user-name> <password>postgres</password> </security> <validation> <check-valid-connection-sql>SELECT 1</check-valid-connection-sql> <validate-on-match>false</validate-on-match> <background-validation>false</background-validation> <use-fast-fail>false</use-fast-fail> </validation> </datasource> <!-- Add this config: end --> <drivers> <!-- Add this config: begin --> <driver name='postgresql-jdbc4' module='org.postgresql'/> <!-- Add this config: end --> </drivers>
To configure your datasource with MySQL take a look here:
http://community.jboss.org/wiki/DataSourceConfigurationInAS7
Business – XML Configurations
Let us see how our persistence.xml will be (this file must be inside the folder src/META-INF):
<?xml version='1.0' encoding='UTF-8'?> <persistence version='1.0' xmlns='http://java.sun.com/xml/ns/persistence' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd'> <persistence-unit name='CrudPU' transaction-type='JTA'> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/CrudDS</jta-data-source> <properties> <property name='hibernate.hbm2ddl.auto' value='update'/> </properties> </persistence-unit> </persistence>
We got a very simple code; it is just pointing to a datasource and the option to generate all the database tables with “update”.
Add the EJB project to the JBoss.
Create the database in the Postgres and start the JBoss; after you started it the JPA will create the tables.
Check the image bellow to see the tables/sequences that the JPA created for us.
Create a file named “jboss-web.xml” inside the WEB-INF folder and write the code bellow in it:
<?xml version='1.0' encoding='UTF-8'?> <jboss-web> <!-- URL to access the web module --> <context-root>CrudJSF</context-root> <!-- Realm that will be used --> <security-domain>java:/jaas/CrudJSFRealm</security-domain> </jboss-web>
In the file above we set up the Realm that our application will use. Let us insert the users in the database that will do the login by the JAAS (if you want to see more details about JAAS you can see it here: User Login Validation with JAAS and JSF). I will not get in the JAAS details because you can find every step detailed in the previous link.
See in the image bellow the data that I inserted manually in the database (you should do the same):
Continue to the second part of the tutorial.
Reference: Full WebApplication JSF EJB JPA JAAS from our JCG partner Hebert Coelho at the uaiHebert blog.
Hi, I am NetBeans user. It is possible to use Maven build system for JavaEE in Eclipse? I trying with Geronimo and I faild
no
I performed the same steps. but tables are not created dynamically when i deploy project on jboss 7. Can you please help me?
Same problem here
I performed the above steps using Eclipse (juno) ,sqlserver 2008 r2 and Jboss 7.1 AS but I am getting following error as the server is started.
11:33:44,011 ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads – 1) {“JBAS014653: Composite operation failed and was rolled back. Steps that failed:” => {“Operation step-2” => {“JBAS014771: Services with missing/unavailable dependencies” => [“jboss.persistenceunit.”CrudEap.ear/CrudEjb.jar#CrudPU”jboss.naming.context.java.CrudDSMissing[jboss.persistenceunit.”CrudEap.ear/CrudEjb.jar#CrudPU”jboss.naming.context.java.CrudDS]”]}}}
i have these problem when i run the server (JBoss 7.1)
New missing/unsatisfied dependencies:service jboss.security.security-domain.CrudJSFRealm (missing) dependents: [service jboss.web.deployment.default-host./CrudJSF.realm]
Hi Islam,
I have got the same error, could you fix it?
Hi,
Maybe, you could be a beginer java programer because you are writing the hasCode method in the model layer using the ID attribute and it is wrong, very wrong, it is not efficient and you will have performance issues.
Regards,
David
hello i am a netbean user , actually i am developing a program using jsf ejb and jpa ,i am facing a problem.My problem is the following one: to find a object in from the datatable is ok but actually i just want to find an object by key and i don’t want the found oject to appear in the datatable but rather in the tabulation (input text html).please someone can help me ??