Translating the NetBeans Generated JPA Controller to a Container Environment for GlassFish

The NetBeans New File wizards greatly simplify writing boilerplate code. One specific instance is the creation of JPA Controller Classes from an Entity Classes. The class file, or files, written for you will contain all the basic methods of JPA for CRUD operations on the entity or entities that you have. The only small issue is that this class is written for a standalone environment such as what you would find in an environment that does not support Context Dependency Injection. To use this class in a GlassFish environment or other container we have to make some minor changes.

When working with GlassFish the first step is to create the glassfish-resources.xml and then the persistence.xml file. If the database and its tables have not been created yet then this is the time to do this. Now create the Entity Classes from Database, also shown in the New File dialog below.

With all this in place you simply have to create a New File for the project in the category Persistence and the File Type of JPA Controller Classes from Entity Classes.

Image01

The next dialog will ask you which entities you wish to have a controller class written for. It should show you the entities you have created for your project. They will appear in the Available Entity Classes box and you use the buttons to move the ones that you want. In my example there is just one entity and I have added it to the Selected Entities Classes box.

Image02

In the next step you must select the package name for the classes that will be created for you. You can use a package that already exists.

Image03

When you Finish you will see the package you created with a file that has the name of the Entity class followed by JpaController.java. In my example it is FishJpaController.java. You will also find an additional package that ends in exceptions that contains custom Exception classes that provide more informative exception types.

Image04

When you open the file you will see the class that has been written for you.

package com.kenfogel.beans;

import com.kenfogel.beans.exceptions.NonexistentEntityException;
import com.kenfogel.beans.exceptions.RollbackFailureException;
import com.kenfogel.entities.Fish;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.transaction.UserTransaction;

/**
 *
 * @author Ken
 */
public class FishJpaController implements Serializable {

    public FishJpaController(UserTransaction utx, EntityManagerFactory emf) {
        this.utx = utx;
        this.emf = emf;
    }
    private UserTransaction utx = null;
    private EntityManagerFactory emf = null;

    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    public void create(Fish fish) throws RollbackFailureException, Exception {
        EntityManager em = null;
        try {
            utx.begin();
            em = getEntityManager();
            em.persist(fish);
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void edit(Fish fish) throws NonexistentEntityException, RollbackFailureException, Exception {
        EntityManager em = null;
        try {
            utx.begin();
            em = getEntityManager();
            fish = em.merge(fish);
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = fish.getId();
                if (findFish(id) == null) {
                    throw new NonexistentEntityException("The fish with id " + id + " no longer exists.");
                }
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public void destroy(Integer id) throws NonexistentEntityException, RollbackFailureException, Exception {
        EntityManager em = null;
        try {
            utx.begin();
            em = getEntityManager();
            Fish fish;
            try {
                fish = em.getReference(Fish.class, id);
                fish.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The fish with id " + id + " no longer exists.", enfe);
            }
            em.remove(fish);
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

    public List<Fish> findFishEntities() {
        return findFishEntities(true, -1, -1);
    }

    public List<Fish> findFishEntities(int maxResults, int firstResult) {
        return findFishEntities(false, maxResults, firstResult);
    }

    private List<Fish> findFishEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Fish.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

    public Fish findFish(Integer id) {
        EntityManager em = getEntityManager();
        try {
            return em.find(Fish.class, id);
        } finally {
            em.close();
        }
    }

    public int getFishCount() {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Fish> rt = cq.from(Fish.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            return ((Long) q.getSingleResult()).intValue();
        } finally {
            em.close();
        }
    }

}

The changes that you have to make are quite straightforward. First, we need to make this class a managed bean and change the EntityManager and UserTransaction into Injected references.

@Named
@RequestScoped
public class FishJpaControllerUpdate implements Serializable {

    @Resource
    private UserTransaction utx;

    @PersistenceContext
    private EntityManager en;

NetBeans will help you in adding the necessary imports. The next step is to delete the constructor. As a managed bean you must have a default constructor. If you dislike not seeing a constructor in your class then you can add an empty one.

    /**
     * Default constructor
     */
    public FishJpaControllerUpdate() {
    }

Delete the method getEntityManager(). CDI will take care of creating the EntityManager for you.

The last step is to modify every method in the class that has as a first line:

EntityManager em = null;

We don’t need to call upon getEntityManager nor do we need to close the EntityManager when we are finished.

The create method:

    public void create(Fish fish) throws RollbackFailureException, Exception {
        EntityManager em = null;
        try {
            utx.begin();
            em = getEntityManager();
            em.persist(fish);
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            throw ex;
        } finally {
            if (em != null) {
                em.close();
            }
        }
    }

Becomes:

    public void create(Fish fish) throws RollbackFailureException, Exception {
        try {
            utx.begin();
            em.persist(fish);
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            throw ex;
        }
    }

The query method findFishEntities:

    private List<Fish> findFishEntities(boolean all, int maxResults, int firstResult) {
        EntityManager em = getEntityManager();
        try {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Fish.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
        } finally {
            em.close();
        }
    }

Becomes:

    private List<Fish> findFishEntities(boolean all, int maxResults, int firstResult) {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Fish.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
    }

Clean up the rest of the methods and your controller will look like, with my added comments, the following:

package com.kenfogel.beans;

import com.kenfogel.beans.exceptions.NonexistentEntityException;
import com.kenfogel.beans.exceptions.RollbackFailureException;
import com.kenfogel.entities.Fish;
import java.io.Serializable;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.transaction.UserTransaction;
import javax.annotation.Resource;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
import javax.persistence.PersistenceContext;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;

/**
 *
 * @author kfogel
 */
@Named
@RequestScoped
public class FishJpaControllerUpdate implements Serializable {

    @Resource
    private UserTransaction utx;

    @PersistenceContext
    private EntityManager em;

    /**
     * Default constructor
     */
    public FishJpaControllerUpdate() {
    }

    /**
     * Take a new or detached entity and add it as a new record in the table
     * 
     * @param fish
     * @throws RollbackFailureException
     * @throws Exception 
     */
    public void create(Fish fish) throws RollbackFailureException, Exception {
        try {
            utx.begin();
            em.persist(fish);
            utx.commit();
        } catch (Exception ex) {
            try {
                utx.rollback();
            } catch (Exception re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            throw ex;
        }
    }

    /**
     * Take a detached entity and update the matching record in the table
     * 
     * @param fish
     * @throws NonexistentEntityException
     * @throws RollbackFailureException
     * @throws Exception 
     */
    public void edit(Fish fish) throws NonexistentEntityException, RollbackFailureException, Exception {
        try {
            utx.begin();
            fish = em.merge(fish);
            utx.commit();
        } catch (NotSupportedException | SystemException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SecurityException | IllegalStateException ex) {
            try {
                utx.rollback();
            } catch (IllegalStateException | SecurityException | SystemException re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Integer id = fish.getId();
                if (findFish(id) == null) {
                    throw new NonexistentEntityException("The fish with id " + id + " no longer exists.");
                }
            }
            throw ex;
        }
    }

    /**
     * Delete the record that matched the primary key. Verify that the record exists before deleting it.
     * 
     * @param id
     * @throws NonexistentEntityException
     * @throws RollbackFailureException
     * @throws Exception 
     */
    public void destroy(Integer id) throws NonexistentEntityException, RollbackFailureException, Exception {
        try {
            utx.begin();
            Fish fish;
            try {
                fish = em.getReference(Fish.class, id);
                fish.getId();
            } catch (EntityNotFoundException enfe) {
                throw new NonexistentEntityException("The fish with id " + id + " no longer exists.", enfe);
            }
            em.remove(fish);
            utx.commit();
        } catch (NotSupportedException | SystemException | NonexistentEntityException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SecurityException | IllegalStateException ex) {
            try {
                utx.rollback();
            } catch (IllegalStateException | SecurityException | SystemException re) {
                throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
            }
            throw ex;
        }
    }

    /**
     * Return all the records in the table
     * 
     * @return 
     */
    public List<Fish> findFishEntities() {
        return findFishEntities(true, -1, -1);
    }

    /**
     * Return some of the records from the table. Useful for paginating.
     * 
     * @param maxResults
     * @param firstResult
     * @return 
     */
    public List<Fish> findFishEntities(int maxResults, int firstResult) {
        return findFishEntities(false, maxResults, firstResult);
    }

    /**
     * Either find all or find a group of fish
     * 
     * @param all True means find all, false means find subset
     * @param maxResults Number of records to find
     * @param firstResult Record number to start returning records
     * @return 
     */
    private List<Fish> findFishEntities(boolean all, int maxResults, int firstResult) {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            cq.select(cq.from(Fish.class));
            Query q = em.createQuery(cq);
            if (!all) {
                q.setMaxResults(maxResults);
                q.setFirstResult(firstResult);
            }
            return q.getResultList();
    }

    /**
     * Find a record by primary key
     * 
     * @param id
     * @return 
     */
    public Fish findFish(Integer id) {
            return em.find(Fish.class, id);
    }

    /**
     * Return the number of records in the table
     * 
     * @return 
     */
    public int getFishCount() {
            CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
            Root<Fish> rt = cq.from(Fish.class);
            cq.select(em.getCriteriaBuilder().count(rt));
            Query q = em.createQuery(cq);
            System.out.println("fish count: " + ((Long) q.getSingleResult()).intValue());
            return ((Long) q.getSingleResult()).intValue();
    }
}

You are now ready to use this controller class in your JPA/CDI project.

Email this to someoneTweet about this on TwitterShare on LinkedInShare on Facebook
Posted in Computer Science, Education, GlassFish, JPA | Leave a comment

Configuring a MySQL JDBC Connection Pool and JDBC Resource for GlassFish using NetBeans – Updated

This is an updated version of what was posted on Feb 1, 2015. The original information was accurate but some of the steps were optional and this is clearly indicated in the update.

This tutorial assumes that you have installed the Java EE version of NetBeans 8.02. If you are using Windows then it is further assumed that you have replaced the default GlassFish server instance in NetBeans with a new instance with its own folder for the domain. See my previous article “Creating a New Instance of GlassFish in NetBeans IDE” On an Apple Mac and likely on Linux it is not necessary to do this.

Step 1a: Manually Adding the MySQL driver to the GlassFish Domain

Before we even start NetBeans we must do a bit of preliminary work. With the exception of Derby, GlassFish does not include the MySQL driver or any other driver in its distribution.

Go to the MySql Connector/J download site at http://dev.mysql.com/downloads/connector/j/ and download the latest version. I recommend downloading the Platform Independent version. If your OS is Windows download the ZIP archive otherwise download the TAR archive. You are looking for the driver file named mysql-connector-java-5.1.34-bin.jar in the archive.

Copy the driver file to the lib folder in the directory where you placed your domain. On my system the folder is located at C:\Users\Ken\personal_domain\lib. If GlassFish is already running then you will have to restart it so that it picks up the new library.

Step 1a: Automatically Adding the MySQL driver to the GlassFish Domain

NetBeans has a feature that deploys the database driver to the domain’s lib folder if that driver is in NetBeans’ folder of drivers. On my Windows 8.1 system the MySQL driver can be found in C:\Program Files\NetBeans 8.0.2\ide\modules\ext.

Start NetBeans and go to the Services tab, expand Servers and right mouse click on your GlassFish Server.

Image0120a

Click on Properties and the Servers dialog will appear.

Image0120b

On this dialog you will see a check box labelled Enable JDBC Driver Deployment. By default it is checked.

NetBeans determines the driver to copy to GlassFish from the file glassfish-resources.xml that we will create in Step 4 of this tutorial. Without this file and if you have not copied the driver into GlassFish manually then GlassFish will not be able to connect to the database. Any code in your web application will not work and all you will likely see are blank pages.

Step 1a or Step 1b?

I recommend Step 1a and manually add the driver. The reason I prefer this approach is that I can be certain that the most recent driver is in use. As of this writing NetBeans contains version 5.1.23 of the connector but the current version is 5.1.34.

If you copy a driver into the lib folder then NetBeans will not replace it with an older driver even if the check box on the Server dialog is checked. NetBeans does not replace a driver if one is already in place.

If you need a driver that NetBeans does have a copy of then Step 1b is your only choice.

Step 2: Create a Database Connection in NetBeans

One feature I have always liked in NetBeans is that it has an interface for working with databases. All that is required is that you create a connection to the database. It also has additional features for managing a MySQL server but we won’t need those. If you have not already started your MySQL DBMS then do that now. I assume that the database you wish to connect to already exists.

Go to the Services tab and right mouse click on New Connection.

Image0120c

In the next dialog you must choose the database driver you wish to use. It defaults to Java DB (Embedded). Pull down the combo box labeled Driver: and select MySQL (Connector/J driver).

Image0220

 

Click on Next and you will now see the Customize Connection dialog. Here you can enter the details of the connection. On my system the server is localhost and the database name is Aquarium. Here is what my dialog looks like.

Image0320

Notice the Test Connection button. I have clicked on mine and so I have the message Connection Succeeded. Click on Next.

Image0420

There is nothing to do on this dialog so click on Next.

Image0520

On this last dialog you have the option of assigning a name to the connection. By default it uses the URL but I prefer a more meaningful name. I have used AquariumMySQL.

Image0620

Click on Finish and the connection will appear under Databases.

Image0720

If the icon next to AquariumMySQL has what looks like a crack in it similar to the jdbc:derby connection then this means that a connection to the database could not be made. Verify that the database is running and is accessible. If it is then delete the connection and start over.

Having a connection to the database in NetBeans is invaluable. You can interact with the database directly and issue SQL commands. As a MySQL user this means that I do not need to run the MySQL command line program to interact with the database.

Step 3: Create a Web Application Project in NetBeans

If you have not already done so create a New Project in NetBeans. I require my students to create a New Project in the Maven category of a Web Application project.

Image0820

Click on Next. In this dialog you can give the project a name and a location in your file system. The Artifact Id, Group Id and Version are used by Maven.

Image0920a

 

The final dialog lets you select the application server that your application will use and the version of Java EE that your code must be compliant with.

Image0920b

Here is my project ready for the next step.

Image0920

Step 4: Create the GlassFish JDBC Resource

For GlassFish to manage your database connection you need to set up two resources, a JDBC Connection Pool and a JDBC Resource. You can create both in one step by creating a GlassFish JDBC Resource because you can create the Connection Pool as part of the same operation.

Right mouse click on the project name and select New and then Other …

Image1020

Scroll down the Categories list and select GlassFish. In the File Types list select JDBC Resource.

Image1120

Click on Next. The next dialog is the General Attributes. Click on the radio button for Create New JDBC Connection Pool. In the text field JNDI Name enter a name that is unique for the project. JNDI names for connection resources always begin with jdbc/ followed by a name that starts with a lower case letter. I have used jdbc/myAquarium. Do not prefix the name with java:app/ as some tutorials suggest. An upcoming article will explain why.

Image1220

Click on Next. There is nothing for us to enter on the Properties dialog.

Image1320

Click on Next. On the Choose Database Connection dialog we will give our connection pool a name and select the database connection we created in Step 2. Notice that in the list of available connections you are shown the connection URL and not the name you assigned to it back in Step 2.

Image1420

Click on Next. On the Add Connection Pool Properties dialog you will see the connection URL and the user name and password. We do need to make one change. The resource type shows javax.sql.DataSource and we must change it to javax.sql.ConnectionPoolDataSource.

Image1520

Click on Next. There is nothing we need to change on Add Connection Pool Optional Properties so click on Finish.

A new folder has appeared in the Projects view named Other Sources. It contains a sub folder named setup. In this folder is the file glassfish-resources.xml.

Image1620

The glassfish-resources.xml file will contain the following. I have reformatted the file for easier viewing.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
    <jdbc-resource enabled="true" jndi-name="jdbc/myAquarium" object-type="user" pool-name="aquariumPool">
        <description/>
    </jdbc-resource>
    <jdbc-connection-pool allow-non-component-callers="false" 
                        associate-with-thread="false" 
                        connection-creation-retry-attempts="0" 
                        connection-creation-retry-interval-in-seconds="10" 
                        connection-leak-reclaim="false" 
                        connection-leak-timeout-in-seconds="0" 
                        connection-validation-method="auto-commit" 
                        datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" 
                        fail-all-connections="false" idle-timeout-in-seconds="300" 
                        is-connection-validation-required="false" is-isolation-level-guaranteed="true" 
                        lazy-connection-association="false" 
                        lazy-connection-enlistment="false" 
                        match-connections="false" 
                        max-connection-usage-count="0" 
                        max-pool-size="32" 
                        max-wait-time-in-millis="60000" 
                        name="aquariumPool" 
                        non-transactional-connections="false" 
                        pool-resize-quantity="2" 
                        res-type="javax.sql.ConnectionPoolDataSource" 
                        statement-timeout-in-seconds="-1" 
                        steady-pool-size="8" 
                        validate-atmost-once-period-in-seconds="0" 
                        wrap-jdbc-objects="false">
        <property name="URL" value="jdbc:mysql://localhost:3306/Aquarium?zeroDateTimeBehavior=convertToNull"/>
        <property name="User" value="fish"/>
        <property name="Password" value="fish"/>
    </jdbc-connection-pool>
</resources>

OPTIONAL Step 5: Configure GlassFish with glassfish-resources.xml

The glassfish-resources.xml file, when included in the application’s WAR file in the WEB-INF folder, can configure the resource and pool for the application when it is deployed in GlassFish. When the application is un-deployed the resource and pool are removed. If you want to set up the resource and pool permanently in GlassFish then follow these steps.

Go to the Services tab and select Servers and then right mouse click on GlassFish. If GlassFish is not running then click on Start.

With the server started click on View Domain Admin Console.

Image1720

Your web browser will now open and show you the GlassFish console. If you assigned a user name and password to the server you will have to enter this information before you see the console.

Image1820

In the Common Tasks tree select Resources. You should now see in the panel adjacent to the tree the following:

Image1920

Click on Add Resources. You should now see:

Image2020

In the Location click on Choose File and locate your glassfish-resources.xml file. Mine is found at D:\NetBeansProjects\GlassFishTutorial\src\main\setup. You should now see:

Image2120

Click on OK. If everything has gone well you should see:

Image2220

The final task in this step is to test if the connection works. In the Common Tasks tree select Resources, JDBC, JDBC Connection Pools and aquariumPool.

Image2320

Click on Ping. You should see:

Image2520

The most common reason for the Ping to fail is that the database driver is not in the domain’s lib folder. Go to Step 1a and manually add the driver.

The resources are now visible in NetBeans.

Image2620

Having the resource and pool add to GlassFish permanently will allow other applications to share this same resource and pool.

You are now ready to code!

 

 

 

 

 

Email this to someoneTweet about this on TwitterShare on LinkedInShare on Facebook
Posted in Computer Science, Courses, GlassFish, JEE, Maven, MySQL, NetBeans | 3 Comments