Programming
30 May 2012 0 Comments

Using @DataSourceDefinition in Java EE 6 With Postgresql

Introduction

Java EE applications use DataSource objects when they access relational databases through the JDBC API. Typically the Datasource that should be used is referenced by its Java Naming and Directory Interface (JNDI) name in the persistence.xml file:

>java:app/env/myDatasource>

The Datasource details (host, username, password, database type) for this JNDI name need to be declared somewhere. Prior to Java EE 6, you could create a DataSource object using vendor-specific mechanisms. This could be a deployment descriptor for the application server in the WAR, e.g. glassfish-web.xml or XML configuration files in the application server directory.

In Java EE 6 the @DataSourceDefinition annotation was introduced. With this annotation you can declare ‘application server agnostic’ datasources directly in your code. While this is usually a bad idea for production code, it can be very useful for testing, since you don’t have to change the configuration of the application server. You can just deploy the WAR in any application server and it will run.

In this example we run through the steps for setting up a JPA project with a Postgresql database connection using the @DataSourceDefinition annotation.

1. Install Postgresql Driver in Application Server

First, make sure that the application server is set up to support Postgresql connections. For Glassfish 3 we need to install the Postgresql JDBC drivers.

  1. Download the latest JDBC drivers at the Postgresql website.
  2. Download the driver file postgresql-.jdbc4.jar and copy it to /glassfish/lib/.

For other application servers refer to the documentation.

2. Define Datasource With @DataSourceDefinition Annotation

Next we define the details of the datasource named java:app/env/myDatasource using the @DataSourceDefinition annotation in the Java code. We create a special class for this purpose, in DbConfiguration.java:

import javax.annotation.sql.DataSourceDefinition;
 
@DataSourceDefinition(name = "java:app/env/myDatasource",
                minPoolSize = 0,
                initialPoolSize = 0,
                className = "org.postgresql.ds.PGSimpleDataSource",
                serverName="localhost",
                user = "admin",
                password = "admin",
                databaseName = "test"
)
 
public class DbConfiguration {
}

When the application server deploys the application, all @DataSourceDefinition annotations are processed. The application server will look in all classes, so it doesn’t matter where you put the definition.

Note: you can also define a datasource in the web.xml file that is included in the WAR file.:

   >
     >java:app/env/myDatasource>
     >org.postgresql.ds.PGSimpleDataSource>
     >localhost>
     >5432>
     >test>
     >admin>
     >admin>
   >

3. Add Datasource to persistence.xml

Our persistence.xml is quite simple, referencing the data source named java:app/env/myDatasource with the JTA transaction type.

 version="1.0" encoding="UTF-8"?>
 version="2.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_2_0.xsd">
         name="myUnit" transaction-type="JTA">
                >java:app/env/myDatasource>
        >
>

Using the Datasource

Now we can make a simple JSF 2.0 web application that uses the database. Let’s make a simple entity with a ‘name’ field.

NamedEntity.java

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
 
@Entity
@NamedQuery(name="getAll", query="SELECT c from NamedEntity c")
public class NamedEntity implements Serializable {
        private static final long serialVersionUID = 1L;
 
        @Id
        private String name;
 
        public String getName() {
                return this.name;
        }
 
        public void setName(String name) {
                this.name = name;
        }
}

And we add NamedEntity to our persistence unit:

     name="myUnit" transaction-type="JTA">
        >java:app/env/myDatasource>
        >NamedEntity>
    >

We also need a bean that retrieves the names, and makes them available in the JSF page. Since we have declared transaction-type="JTA" in persistence.xml, we can use the @PersistenceContext annotation. This tells the application server to inject a reference to the appropriate EntityManager instance at run-time. In this case it means we will get an EntityManger for the myUnit persistence unit.

TestBean.java

import java.io.Serializable;
import java.util.List;
 
import javax.annotation.sql.DataSourceDefinition;
import javax.faces.bean.ApplicationScoped;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
 
@Named("test")
@ApplicationScoped
public class TestBean implements Serializable
{
        private static final long serialVersionUID = 1L;
 
        // EntityManager is injected here by application server
        @PersistenceContext
        private EntityManager em;
 
        public String getNames()
        {
                TypedQuery<NamedEntity> query = em.createNamedQuery("getAll", NamedEntity.class);
                List<NamedEntity> results = query.getResultList();
 
                StringBuilder result = new StringBuilder("The name are: [");
                String separator = "";
                for (NamedEntity entity: results)
                {
                        result.append(separator).append(entity.getName());
                        separator = ", ";
                }
                result.append("]");
                return result.toString();
        }
}

Then in our JSF page we can reference the TestBean class through an EL expression:

   value="#{test.getNames()}"/>

This code should work without problems, printing all rows from the database, e.g.:

The names are: [Jack, John, Dave]

Common Glassfish Problems

Some errors you may run into when using Glassfish 3 are:

WebappClassLoader unable to load resource

javax.servlet.ServletException: WEB9031: WebappClassLoader unable to load resource 
[org.postgresql.jdbc4.Jdbc4PreparedStatement], because it has not yet been started, or was already stopped

This means the Postgresql JDBC driver cannot be found. Copy the JDBC JAR file to /glassfish/lib/ and restart the server.

No PasswordCredential found

WARNING: RAR5038:Unexpected exception while creating resource for pool 
__SYSTEM/pools/__datasource_definition/testApp/java:app/env/myDatasource. 
Exception : javax.resource.spi.SecurityException: No PasswordCredential found
WARNING: RAR5117 : Failed to obtain/create connection from connection pool 
[ __SYSTEM/pools/__datasource_definition/testApp/java:app/env/myDatasource]. 
Reason : com.sun.appserv.connectors.internal.api.PoolingException: No PasswordCredential found
WARNING: RAR5114 : Error allocating connection : 
[Error in allocating a connection. Cause: No PasswordCredential found]

This error indicates the password field for a datasource was left blank. Even though it’s perfectly valid to connect to a database without a password, Glassfish does not like this — it will completely ignore empty properties. Thankfully there is a special meta-string that can be used instead property values to represent a zero length string: ().

ERROR: relation ‘namedentity’ does not exist

Internal Exception: org.postgresql.util.PSQLException: ERROR: relation "namedentity" does not exist
Error Code: 0
Call: INSERT INTO NAMEDENTITY (NAME) VALUES (?)
        bind => [1 parameter bound]
Query: InsertObjectQuery(my.package.namedentity@7f96dfa4)

This means the table associated with an entity does not exist in the database yet. You can tell the JPA implementation to automatically create the tables, but since this is outside the spec there is no fixed syntax. For EclipseLink (the JPA implementation inside Glassfish 3) you have to add two properties to your persistence.xml file:

     name="myUnit" transaction-type="JTA">
        
         name="eclipselink.ddl-generation" value="create-tables" />
         name="eclipselink.ddl-generation.output-mode" value="database" />
    >

Resources

Tags: datasourcedefinition, entitymanager,