DataSource Resource Definition in Java EE 6

by Jagadish Ramu

Please note: This blog was updated on May 7, 2010.

Java EE applications use DataSource objects when they access relational databases through the JDBC API. A DataSource has a set of properties that identify and describe the real-world data source that it represents. These properties include information such as the location of the database server, the name of the database, and the network protocol to use to communicate with the server. In addition, a DataSource object works with a Java Naming and Directory Interface (JNDI) naming service. After a DataSource object is registered with a JNDI naming service, an application can use the JNDI API to access that DataSource object, which can then be used to connect to the datasource it represents.

Prior to Java EE 6, you could create a DataSource object using vendor-specific mechanisms, such as commands, and use the DataSource object in the application. However, Java EE 6 makes datasource definition more flexible. It introduces a new datasource definition resource that you can declare portably for database connectivity across any Java EE 6-compatible application server. You can declare datasource definitions either through annotations or through the use of deployment descriptors.

This Tech Tip shows you how to create a datasource definition using either annotations or deployment descriptors. It also includes a sample application that demonstrates the use of these features.

Creating Datasource Definitions Using Annotations

Java EE 6 provides two new annotations for creating datasource definitions: @DataSourceDefinition and @DataSourceDefinitions. Both of these annotations are in the javax.annotation.sql package. You use the @DataSourceDefinition annotation to create a single datasource definition. You use the @DataSourceDefinitions annotation to create multiple datasource definitions.

@DataSourceDefinition Annotation

You can use the @DataSourceDefinition annotation to create a datasource definition. You can specify the annotation in an application component class such as an application client, servlet, or Enterprise JavaBeans (EJB) component. This defines a DataSource object and registers it with JNDI. You configure the DataSource object by setting the annotation elements with commonly used DataSource properties. You can specify additional standard and vendor-specific properties in the properties element of the annotation.

For example, the following annotation creates a datasource definition for a Derby database:

   @DataSourceDefinition(name = "java:app/env/Servlet_DataSource",
      minPoolSize = 0,
      initialPoolSize = 0,
      className = "org.apache.derby.jdbc.ClientXADataSource",
      user = "APP",
      password = "APP",
      databaseName = "testdb",
      properties = {"connectionAttributes=;create=true"}
   )

The datasource definition is uniquely identified by the name element. This is the JNDI name by which the datasource will be registered. Notice that the name specified in the name element begins with a namespace scope, in this case, java:app. Java EE 6 introduces application component environment namespaces, which includes the following scopes.

  • java:comp. Names in this namespace have per-component visibility.
  • java:module. Names in this namespace are shared by all components in a module, for example, the EJB components defined in an a ejb-jar.xml file.
  • java:app. Names in this namespace are shared by all components and modules in an application, for example, the application-client, web, and EJB components in an .ear file.
  • java:global. Names in this namespace are shared by all the applications in the server.

Depending on the namespace scope you specify in the name element, you can make the datasource available across a module, an application, or globally across a server. If you prefix the name element value with:

  • java:comp/env/, the datasource will be available for the component in which it is defined, such as a servlet, EJB, or application client component.
  • java:module/env/, the datasource will be available for all the EJB components defined in its ejb-jar.xml file.
  • java:app/env/, the datasource will be available for all the components and modules in the application, such as EJB, servlet, and application client components.

@DataSourceDefinitions Annotation

You can use the @DataSourceDefinitions annotation to create multiple datasource definitions in a component class. You specify each datasource definition in a value element in the annotation. Here is an example that creates in an EJB class multiple datasource definitions for a Derby database:

   @DataSourceDefinitions(
      value = {

        @DataSourceDefinition(name = "java:app/env/HelloStatefulEJB_DataSource",
           minPoolSize = 0,
           initialPoolSize = 0,
           className = "org.apache.derby.jdbc.ClientXADataSource",
           portNumber = 1527,
           serverName = "localhost",
           user = "APP",
           password = "APP",
           databaseName = "testdb",
           properties = {"connectionAttributes=;create=true"}
                   ),

        @DataSourceDefinition(name = "java:comp/env/HelloStatefulEJB_DataSource",
           minPoolSize = 0,
           initialPoolSize = 0,
           className = "org.apache.derby.jdbc.ClientXADataSource",
           portNumber = 1527,
           serverName = "localhost",
           user = "APP",
           password = "APP",
           databaseName = "testdb",
           properties = {"connectionAttributes=;create=true"}
        )
      }
   )
   @Stateful
   public class HelloStatefulEJB implements HelloStateful {
   ...
   ...
   }

Creating Datasource Definitions Using a Deployment Descriptor

You can create a datasource definition resource using a deployment descriptor in an application.xml, application-client.xml, web.xml, or ejb-jar.xml file. For example, the following deployment descriptor creates the same datasource definition as was defined in the previous @DataSourceDefinition annotation example:

   <data-source>
     <name>java:app/env/Application_Level_DataSource</name>
     <class-name>org.apache.derby.jdbc.ClientXADataSource</class-name>
     <server-name>localhost</server-name>
     <port-number>1527</port-number>
     <database-name>testdb</database-name>
     <user>APP</user>
     <password>APP</password>
     <property>
       <name>connectionAttributes</name>
       <value>;create=true</value>
     </property>
   </data-source>

You've seen two examples that create the same datasource definition, one using an annotation and one using a deployment descriptor. In fact, it is possible to create two datasource definitions with the same name in this way. In that case, the values specified in the deployment descriptor take precedence over those specified in the annotation. For example, if you create two datasource definitions with the same name, one using an annotation and one using a deployment descriptor, and you specify a database name is each, the database name that you specified in the deployment descriptor will be honored. However, if you specify a value for an element in an annotation and you don't specify an equivalent element in a deployment descriptor, the value from the annotation will be merged with the deployment descriptor-based information.

Sample Application

A sample application accompanies this tip. The application demonstrates datasource definition using annotations and deployment descriptors, and it does it for various types of Java EE components and for various namespace scopes. The application includes the following Java EE components:

  • Web component: Servlet.java
  • EJB components: HelloStatefulEJB.java and HelloEJB.java
  • Application client: Client.java
  • The application is supplied a datasource definition name. It then does a lookup of the datasource in the application client, EJB, and servlet components. Based on the availability of the resource in the component's scope, the application either uses the provided datasource or a default datasource, java:app/env/Application_DD_DataSource.

    Here are the datasource definitions that are created or exported by the application:

    • java:app/env/Application_DD_DataSource
    • java:comp/env/Servlet_DD_DataSource
    • java:module/env/Servlet_DataSource
    • java:app/env/Servlet_DataSource
    • java:comp/env/HelloStatefulEJB_DataSource
    • java:app/env/HelloStatefulEJB_DataSource
    • java:comp/env/HelloEJB_DataSource
    • java:module/env/HelloEJB_DataSource
    • java:app/env/HelloEJB_DD_DataSource
    • java:comp/env/Appclient_DD_DataSource
    • java:module/env/Appclient_DD_DataSource
    • java:app/env/Appclient_DataSource

    From the name and the namespace scope of the resource, the component in which the resource is defined can be identified. For example, for the datasource definition named java:app/env/HelloEJB_DD_DataSource, the namespace scope is java:app and the resource is defined for "HelloEJB" in a deployment descriptor, "DD".

    To run the application, do the following:

    1. If you haven't already done so, download GlassFish v3. Set the environment variable GF_HOME to where you installed GlassFish v3.
    2. Ensure that you have an installed version of the Java Platform Standard Edition (Java SE) 6 SDK.
    3. Ensure that the PATH environment variable includes JAVA_HOME/bin, where JAVA_HOME is set to where the Java SE 6 SDK is installed.
    4. Ensure that the ANT tool is installed. It should be installed as part of GlassFish v3. Also ensure that the PATH environment variable includes ANT_HOME/bin, where ANT_HOME is set to where the ANT tool is installed.
    5. Start the GlassFish v3 application server by entering the following command:
         <GF_HOME>/bin/asadmin start-domain
      
    6. Start the Derby database that is packaged with the GlassFish v3 by entering the following command:
         <GF_HOME>/bin/asadmin start-database
      
    7. Download and extract the sample application, DSD.zip.
    8. Change to the sample directory. If your installation of GlassFish v3 requires an administration password, specify the password as the value of the admin.password property in the config.properties file.
    9. Execute the following command:
         ant all
      

      The command compiles, assembles, deploys, and runs the application. It then undeploys the application.

      In response, you should see output for various datasources. Here is the output you should see for the datasource named java:app/env/Servlet_DataSource:

          [exec] Mode : appclient
          [exec] Data-Source name : java:app/env/Servlet_DataSource
          [exec] ----------------------------------------------------------------------------------------------------------
          [exec] REQUESTED DATA SOURCE                  : java:app/env/Servlet_DataSource
          [exec] ACTUAL DATA SOURCE USED              : java:app/env/Servlet_DataSource
          [exec] RESULT                                                   : DATASOURCE ACCESSIBLE
          [exec] ----------------------------------------------------------------------------------------------------------
          [exec]
          [exec] Mode : servlet
          [exec] Data-Source name : java:app/env/Servlet_DataSource
          [exec] ----------------------------------------------------------------------------------------------------------
          [exec] REQUESTED DATA SOURCE                : java:app/env/Servlet_DataSource
          [exec] ACTUAL DATA SOURCE USED            : java:app/env/Servlet_DataSource
          [exec] RESULT                                                 : DATASOURCE ACCESSIBLE
          [exec] ----------------------------------------------------------------------------------------------------------
          [exec]
          [exec] Mode : stateful_ejb
          [exec] Data-Source name : java:app/env/Servlet_DataSource
          [exec] ----------------------------------------------------------------------------------------------------------
          [exec] REQUESTED DATA SOURCE                : java:app/env/Servlet_DataSource
          [exec] ACTUAL DATA SOURCE USED             : java:app/env/Servlet_DataSource
          [exec] RESULT                                                 : DATASOURCE ACCESSIBLE
          [exec] ----------------------------------------------------------------------------------------------------------
          [exec]
          [exec] Mode : stateless_ejb
          [exec] Data-Source name : java:app/env/Servlet_DataSource
          [exec] ----------------------------------------------------------------------------------------------------------
          [exec] REQUESTED DATA SOURCE                : java:app/env/Servlet_DataSource
          [exec] ACTUAL DATA SOURCE USED            : java:app/env/Servlet_DataSource
          [exec] RESULT                                                 : DATASOURCE ACCESSIBLE
          [exec] ----------------------------------------------------------------------------------------------------------
       

      In the above output, DATASOURCE ACCESSIBLE in the RESULT rows indicates that the datasource named java:app/env/Servlet_DataSource is available across all components, that is, across the EJB, servlet, and application client components.

      Similarly, here is what the output for the resource named java:module/env/HelloEJB_DataSource should look like :

          [exec] Mode : appclient
      	[exec] Data-Source name : java:module/env/HelloEJB_DataSource
      	[exec] ----------------------------------------------------------------------------------------------------------
      	[exec] REQUESTED DATA SOURCE                : java:module/env/HelloEJB_DataSource
      	[exec] ACTUAL DATA SOURCE USED            : java:global/default-datasource
      	[exec] RESULT                                                 : DATASOURCE NOT ACCESSIBLE
      	[exec] ----------------------------------------------------------------------------------------------------------
      	[exec]
      	[exec] Mode : servlet
      	[exec] Data-Source name : java:module/env/HelloEJB_DataSource
      	[exec] ----------------------------------------------------------------------------------------------------------
      	[exec] REQUESTED DATA SOURCE                : java:module/env/HelloEJB_DataSource
      	[exec] ACTUAL DATA SOURCE USED             : java:global/default-datasource
      	[exec] RESULT                                                 : DATASOURCE NOT ACCESSIBLE
      	[exec] ----------------------------------------------------------------------------------------------------------
      	[exec]
      	[exec] Mode : stateful_ejb
      	[exec] Data-Source name : java:module/env/HelloEJB_DataSource
      	[exec] ----------------------------------------------------------------------------------------------------------
      	[exec] REQUESTED DATA SOURCE                : java:module/env/HelloEJB_DataSource
      	[exec] ACTUAL DATA SOURCE USED            : java:module/env/HelloEJB_DataSource
      	[exec] RESULT                                                 : DATASOURCE ACCESSIBLE
      	[exec] ----------------------------------------------------------------------------------------------------------
      	[exec]
      	[exec] Mode : stateless_ejb
      	[exec] Data-Source name : java:module/env/HelloEJB_DataSource
      	[exec] ----------------------------------------------------------------------------------------------------------
      	[exec] REQUESTED DATA SOURCE                : java:module/env/HelloEJB_DataSource
      	[exec] ACTUAL DATA SOURCE USED            : java:module/env/HelloEJB_DataSource
      	[exec] RESULT                                                 : DATASOURCE ACCESSIBLE
          [exec] ----------------------------------------------------------------------------------------------------------
      

      Here, the RESULT lines indicate that the datasource named java:module/env/HelloEJB_DataSource is available only for the EJB components defined in the ejb-jar.xml file, that is, HelloEJB and HelloStatefulEJB.

      Note that the sample application does a lookup to get access to a resource. However, it is also possible to inject the datasource as follows :

         @Stateless
         public class HelloEJB implements Hello {
      
           @Resource(lookup = "java:app/env/HelloEJB_DataSource")
           private DataSource app;
         ...
         ...
         }
      

      Also note that the sample application defines many datasources in addition to the ones named previously. To run the application for these additional datasources, find the build.xml file in the sample directory. Then uncomment the commented target="runclient" calls.

    Further Reading

    For more information about DataSource resource definition in Java EE 6, see Section EE.5.17 "DataSource Resource Definition" in the Java EE 6 Specification.

    About the Author

    Jagadish Ramu is an engineer in the GlassFish Application Server team. He works in the areas of JDBC, connection pooling, and connectors. He has been involved with the connectors team at Sun since mid-2005. Jagadish holds an M.Tech degree from BITS Pilani, India.

    Comments:

    Thanks Jagdish. Superb and innovative ideas demonstrated for JNDI naming, usage, and examples.

    Posted by lava kafle on December 15, 2009 at 01:19 PM PST #

    Hi there,
    Good to see that the feedback for Java EE 6 was useful and that in the end we have such a feature in the final spec.
    Really looking forward to using it!
    D.

    Posted by GreenEyed on December 18, 2009 at 08:34 PM PST #

    Hi Jagadish,

    Just a small concern, the password is in clear text in the program. If someone inadvertently gets hold of the .class file wouldn't it possible to get hold of the password? I think this annotation has RUNTIME visibility? If it does then may be you should obfuscate the class file if its not being done already?

    Posted by Shreyas on December 20, 2009 at 01:39 AM PST #

    Thanks a lot Jagadish, you have explained the concept of DataSource in very simple and elegant way.

    Posted by vijay waghmode on December 20, 2009 at 06:44 PM PST #

    Simple and clear

    Thank you

    Posted by Sridhar Loka on December 20, 2009 at 11:10 PM PST #

    @Shreyas. Here is a response from Jagadish Ramu:

    Yes, it is clarified in Java EE 6 Specification. Section EE 5.17, Page 126:

    " Of course, we do not recommend including passwords to production
    systems in the code, but it's often useful while testing. Passwords, or other parts of the DataSource definition, can be overridden by a deployment descriptor when the
    application is deployed."

    Posted by Ed Ort on December 21, 2009 at 01:56 AM PST #

    thank you for your article...that is a nice one...i often visit this blog and i enjoy reading all posts...

    Posted by dizi izle on January 22, 2010 at 06:46 PM PST #

    Great write up Jagadish. I'm having a little trouble making it work. Could you take a look at this post --> http://stackoverflow.com/questions/3030483/resource-annotation-is-null-at-run-time

    Posted by Andrew on June 13, 2010 at 02:55 AM PDT #

    This is an excellent post Jagadish although I still do not see the need for defining the Datasources in the java code using the annotations.
    I think one of the advantages of using datasources is to make it configurable outside the source code.

    Posted by Websphere on August 19, 2010 at 08:49 PM PDT #

    Post a Comment:
    Comments are closed for this entry.
    About

    edort

    Search

    Archives
    « April 2014
    SunMonTueWedThuFriSat
      
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
       
           
    Today