2013-02-28

Tutorial: exposing RESTful web services using EJB and Hibernate/JPA under JBoss AS

Some people think that Enterprise Java Beans (EJBs) deployed on EJB containers (Glassfish, JBoss, etc...) are “complicated” whereas RESTful web services deployed on servlet containers (e.g. Tomcat) are “simple”, and the two things cannot go together.

Actually, you can take the best of the two worlds, by exposing your EJBs with a REST interface. This allows you to exploit all the capabilities of an Enterprise Application Server (dependency injection, container-managed distributed transactions, etc...) while making life simpler for your clients, and without the need of shipping tons of libraries (e.g. Jersey, Hibernate, etc...) with your WAR.

In this tutorial we’ll create a web application interfaced with a MySQL database via Hibernate/JPA that runs in a EJB container (JBoss AS 7.1) and exposes a RESTful web service.

  1. Let’s assume you already have installed Eclipse Indigo for Java EE developers, the JRE/JDK bin directory is in your PATH, and the JAVA_HOME environment variable is correctly set to your JRE/JDK home directory.
    Also, you should have a properly configured MySQL database up and running.

  2. First of all, download MySQL Connector/J, extract the archive and get the JAR file named like mysql-connector-java-x.x.xx-bin.jar.

  3. Download JBoss AS 7.1 and unpack it. Start it by running bin/standalone.bat (Windows) or bin/standalone.sh (*nix).
    Run the script bin/add-user.bat (or .sh) to create a management user, and then point your browser to http://localhost:9990/ to access the Administration Console.

  4. Go to “Manage Deployments”, deploy the MySQL Connector JAR file (mysql-connector-java-x.x.xx-bin.jar) and enable it. Now you should have something like this:

    (Alternatively, you can install the MySQL connector as a module.)

    Go to “Profile” (top-right corner) and then “Datasources”. Add a new datasource, with name “Tutorial” and JNDI Name java:/tutorial. When asked, pick the MySQL driver you’ve deployed before and then specify the JDBC connection parameters (leaving out “Security domain”).
    Obviously, the connection parameters depend on your local configuration, but I suggest you to create an ad-hoc database and user for this tutorial.

    After you added the datasource, select and enable it. Now you should see something like this:

  5. Launch Eclipse, open the “Preferences”, go to “Server” > “Runtime Environments”, and click “Add”. This window will appear:

    You may have noticed an entry named “JBoss”: please ignore it.
    Instead, click on “Download additional server adapters”, select “JBossAS Tools”, then click “Next” and follow the installation process.

    Once the installation is complete (it may take a while), restart the IDE and get back to the same window as before:

    Now you have a new entry named “JBoss Community”. Explode it and pick “JBoss 7.1 Runtime”. Click “Next” and follow the instructions. The only thing you have to change is the “Home directory”: set it to the path where you have unpacked JBoss.

  6. Create a new Dynamic Web Project choosing “JBoss 7.1 Runtime” as Runtime Environment. I’ll call the project EjbRest, and use this name for the rest of this tutorial.

  7. Create a new package called example.ejbrest.
    Inside it, create a new class named Customer (it will be the class of the entities we’ll persist in the DB) and put this code inside it:

    package com.example.ejbrest;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.xml.bind.annotation.XmlRootElement;
    
    @Entity
    @XmlRootElement
    public class Customer {
        
        @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
        private int id;
        
        private String name;
        
        private String surname;
    
        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 String getSurname() {
            return surname;
        }
    
        public void setSurname(String surname) {
            this.surname = surname;
        }
    
    }
    

    I think you already know the meaning of the Java Persistence API (JPA) annotations like @Entity, @Id and @GeneratedValue. If not, read a JPA tutorial to learn more.

    In your MySQL database, create a corresponding table and add an example record:

    CREATE TABLE Customer (
            id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
            name VARCHAR(255),
            surname VARCHAR(255)
    );
    
    INSERT INTO Customer (name, surname) VALUES ('John','Smith');
    
  8. Under the src directory of your project, create a directory named META-INF. Inside it, create a file named persistence.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <persistence 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"
        version="1.0">
    
        <persistence-unit name="tutorial">
            <provider>org.hibernate.ejb.HibernatePersistence</provider>
            <jta-data-source>java:/tutorial</jta-data-source>
            <properties>
                <property name="hibernate.archive.autodetection" value="class" />
                <property name="hibernate.format_sql" value="true" />
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
                <property name="hibernate.show_sql" value="true" />
            </properties>
        </persistence-unit>
    
    </persistence>
    

    As you probably know, this defines of a JPA Persistence Unit, that matches with the Datasource you have configured before (please note the JNDI name java:/tutorial).

  9. In the com.example.ejbrest package, create a class named CustomerDAO and put this code inside it:

    package com.example.ejbrest;
    
    import java.util.List;
    import javax.ejb.LocalBean;
    import javax.ejb.Stateless;
    import javax.ejb.TransactionAttribute;
    import javax.ejb.TransactionAttributeType;
    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    
    @Stateless
    @LocalBean
    public class CustomerDAO {
    
        @PersistenceContext
        private EntityManager em;
        
        public Customer getCustomer(int id) {
            return em.find(Customer.class, id);
        }
        
        @TransactionAttribute(TransactionAttributeType.REQUIRED)
        public void addCustomers(List<Customer> customers) {
            for (Customer customer : customers) {
                em.persist(customer);
            }
        }
        
    }
    

    This class is what we call an EJB (Enterprise Java Bean). Its lifecycle will be entirely managed by the container (JBoss AS), and an instance of the EntityManager class (which belongs to the JPA) will be created and injected as needed, by using the information you provided in the persistence.xml file.
    I cannot explain the meaning of all the annotations used here. If you don’t know them, read an EJB tutorial.

    However, the thing here deserving your attention is the persistence and transaction management stuff. Please note the elegance of the persistence context injection (@PersistenceContext) and the declarative transaction model (@TransactionAttribute). Java EE provides you with an effective, intuitive and database-agnostic way of managing transactions.
    In this example, the addCustomers(List<Customer>) method stores the customers in the database from within a transaction: if any error occours at some point, the whole operation fails and no changes are committed to the database.

  10. Now we have to create the RESTful web service. If you already deployed RESTful web services with Jersey under Tomcat, this is nothing new for you.
    Create a class named CustomerWS under the com.example.ejbrest package:

    package com.example.ejbrest;
    
    import java.util.List;
    import javax.ejb.EJB;
    import javax.ejb.LocalBean;
    import javax.ejb.Stateless;
    import javax.ws.rs.GET;
    import javax.ws.rs.POST;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    
    @Path("/customers")
    @Stateless
    @LocalBean
    public class CustomerWS {
    
        @EJB
        private CustomerDAO customersDao;
    
        @GET
        @Path("/{id}")
        public Customer getCustomer(@PathParam("id") int id) {
            return customersDao.getCustomer(id);
        }
        
        @POST
        public void addCustomers(List<Customer> customers) {
            customersDao.addCustomers(customers);
        }
        
    }
    

    Assuming you know the meaning of the @Path, @GET and @POST annotations (if not, have a look at JAX-RS), please note again the elegance of this approach: the CustomerDAO bean is created, managed and injected by the container, with no boilerplate code (like factories, code for creation and disposal, etc...).

  11. Create a class named RestApplication:

    package com.example.ejbrest;
    
    import javax.ws.rs.ApplicationPath;
    import javax.ws.rs.core.Application;
    
    @ApplicationPath("/")
    public class RestApplication extends Application {
    }
    

    This is just a placeholder class telling the container that your application should be deployed as a RESTful web service.

  12. Export your project as a WAR file named EjbRest.war.
    You don’t need to ship any library with it (e.g. Hibernate and Jersey), since JBoss AS 7.1 has already got everything inside. As a consequence, the WAR will just take some kilobyte!

  13. Get back to the JBoss AS Administration Console and deploy the WAR file, by following the same process you did for deploying the MySQL Connector. At the end, you should have something like this:

  14. Point your browser to http://localhost:8080/EjbRest/customers/1. If everything goes right, you’ll get this XML file:

    <customer>
       <id>1</id>
       <name>John</name>
       <surname>Smith</surname>
    </customer>
    

    This means your RESTful web service is up and running!

    You can also test the “add customers” function by POST-ing this XML file to /EjbRest/customers:

    <customers>
       <customer>
          <name>Mark</name>
          <surname>Twain</surname>
       </customer>
       <customer>
          <name>John</name>
          <surname>Doe</surname>
       </customer>
    </customers>
    

That’s it! I’m sorry this tutorial got too long. I probably forgot to mention something important (if so, please post a comment) and I deliberately omitted many details, for the sake of brevity. I really hope you found something valuable in it. If you want, you can download the full source code here.

However, what I’m trying to show is that the approach of exploiting the full power of Java EE, with the use of EJBs and Hibernate/JPA under a fully-featured application server like JBoss AS, has several advantages, such as:

  • No need for external libraries, since the Application Server provides you with everything
  • Distributed container-managed transactions defined with an intuitive and effective declarative model
  • Database-agnostic and fully portable persistence API
  • Trouble-free and light deployment: you don’t need to ship megabytes of libraries and, provided your application obeys Java EE standards, you can deploy anywhere without the need of changing anything
  • Dependency injection directly managed by the container without the need of using DI frameworks like Spring or Guice

Feel free to share your thoughts by posting a comment!

comments powered by Disqus
Fork me on GitHub