Sun Java Solaris Communities My SDN Account Join SDN
 
Enterprise Java Technologies Tech Tips

Using Annotations in Web Applications and How to Get the Best Performance Out of a Java Persistence Implementation

 
In this issue
 
Welcome to the Enterprise Java Technologies Tech Tips for May 26, 2007. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE).

This issue covers:

The Using Annotations in Web Applications tip was developed using the NetBeans IDE and the Java EE 5 SDK. NetBeans IDE 5.5 with the NetBeans Enterprise Pack 5.5 is available in Java EE 5 SDK Update 2, which you can download from the Java EE Downloads page.

The How to Get the Best Performance Out of a JPA Implementation tip was developed using an open source reference implementation of Java EE 5 called GlassFish. You can download GlassFish from the GlassFish Community Downloads page.

You can download the sample archive for the tip Using Annotations in Web Applications.

You can download the sample archive for the tip How to Get the Best Performance Out of a JPA Implementation.

Any use of this code and/or information below is subject to the license terms.

 
Using Annotations in Web Applications
By Shing Wai Chan  

Java EE 5 introduced annotations, a way to simplify the development and configuration of enterprise applications. The March 31, 2007 Tech Tip Using Security Annotations in Enterprise Beans showed how you can use annotations to simplify the development of secure applications that use enterprise beans. Some of the annotations in Java EE 5 are specific to web applications. Examples of this type of annotation are @Resource, @EJB, and @WebServiceRef. Other annotations, such as @RunAs and @DeclareRoles, are related to security. The security-related annotations were introduced in the Using Security Annotations in Enterprise Beans tip.

Although you can specify annotations in various web application components, you can't specify an annotation in a JavaServer Pages (JSP) technology page. However, annotations are supported in web libraries. This means that you can specify annotations in tag libraries and servlet filters, among other places. This gives you a way of securing JSP pages and servlets, provided that you take one additional action: you need to specify appropriate security information in the web.xml file for the web application.

This tip shows you how to construct a secure web application that includes servlets and JSP pages. By configuring the web.xml file for the web application, you can protect the servlets and JSP pages over a Secure Sockets Layer connection. This is a common security approach in a web production environment.

A sample web application package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package).

The Servlet

Let's begin by examining the servlet for the web application. In this example, the servlet invokes an enterprise bean (in this case, a stateless session bean) with a local interface SlessLocal. The servlet passes a message object as a request attribute and then forwards it to a JSP page, display.jsp, for display. Here is the major part of the code for the servlet:


   @DeclareRoles({"arole"})
   @RunAs("myrole")
   public class TestServlet extends HttpServlet {
       private @EJB SlessLocal slessLocal;
       
       public void service(
           HttpServletRequest req, HttpServletResponse resp)
               throws ServletException, IOException {
           if (req.isUserInRole("arole")) {
               String message = slessLocal.hello("World");
               req.setAttribute("EJB_MESSAGE", message);
           }
   
           RequestDispatcher rd = 
               req.getRequestDispatcher("display.jsp");
           rd.forward(req, resp);
       }
   }

The @EJB annotation is used to look up an enterprise bean with the corresponding interface so that the bean can be used by the servlet. The @DeclareRoles annotation defines the role to be used by HttpServletRequest.isUserInRole(String role). The isUserInRole method determines whether the authenticated user is included in the specified role. In this case, only a user in the role "arole" will cause the servlet to retrieve the "message" String and set it as an HttpServletRequest attribute.

The @RunAs annotation specifies that the role "myrole" should be used to access the enterprise bean method SlessLocal.hello(String message).

The Enterprise Bean

Here is the major part of the code for the stateless session bean:

   @Stateless
   @Local({SlessLocal.class})
   public class SlessBean implements SlessLocal {
       @RolesAllowed(value={"myrole"})
       public String hello(String message) {
           return "Hello, " + message + ", " + new Date();
       }
   }

Notice that the hello method is protected through the use of the @RolesAllowed annotation. The annotation specifies that only authenticated users in the role "myrole" can access the hello method.

The JSP and Tag Library

The JSP page, display.jsp, invokes an action in a JSP tag library and passes the attribute EJB_MESSAGE as a parameter in the HttpServletRequest. Here is a snippet of code from the JSP page:

   <%@taglib prefix="di" 
       uri="http://java.sun.com/techtip/webann/test-taglib"%>
   ...
     <di:displayInfo ejbMessage="${requestScope.EJB_MESSAGE}"/>
   ...

The tag handler for the tag reads the value of the ejbMessage parameter and displays it in HTML. It also prints the login timeout for the DataSource. Here is the pertinent code in the tag handler:

   public class DisplayInfoTagHandler extends SimpleTagSupport {
   
      private @Resource(name="jdbc/__default") DataSource ds;
      ...
  
      public void doTag() throws JspException, IOException {
         try {
             JspWriter out = getJspContext().getOut();
             int timeout = ds.getLoginTimeout();
             if (ejbMessage != null && ejbMessage.length() > 0)
             {
                 out.println(
                     "<li> Ejb Message: " + ejbMessage);
             }
             out.println(
                 "<li> DataSource login timeout: " + timeout);
         ...
      }
      public void setEjbMessage(String ejbMessage) {
         this.ejbMessage = ejbMessage;
      }
   }

The @Resource annotation in the tag handler is used to look up the DataSource with the JNDI name, "jdbc/__default". This JNDI name corresponds to the default Derby database. If you want to access the database connection, you could add ds.getConnection() to the code in the tag handler.

Notice too that the tag handler defines a setter method for the parameter ejbMessage.

Securing the Servlet and JSP page

This example takes the approach of protecting the war file for the application by requiring a username and password and by using SSL in the transport layer. The username and password is sent in clear text over the wire. There is no need to modify any Java code or JSP page in the application. To secure the servlet and JSP page in the application all you need to do is configure the web.xml file as follows:

  1. Define a security constraint by specifying a <security-constraint> element. This protects a corresponding URL so that a given role can access it. Note that you can define one or more HTTP methods that the security constraint applies to by specifying <http-method> elements in the security constraint. If you want the security constraint element to apply to all HTTP methods, you simply omit the <http-method> elements.

  2. Indicate that SSL will be used for communication. You do this in the security constraint by specifying a <user-data-constraint> element and within it a <transport-guarantee> element. Set the value of the <transport-guarantee> element to CONFIDENTIAL.

  3. Set the authentication method. You do this by specifying an <login-config> element and within it an <auth-method> element. Set the value of the <auth-method> to BASIC.

Here is a snippet of the web.xml file:

   <security-constraint>
      < web-resource-collection>
         <web-resource-name>Servlet Application
         </web-resource-name>
         <url-pattern>/*</url-pattern>
      </web-resource-collection>
      <auth-constraint>
         <role-name>ttrole</role-name>
      </auth-constraint>
      <user-data-constraint>
         <transport-guarantee>CONFIDENTIAL
         </transport-guarantee>
      </user-data-constraint>
   </security-constraint>
   <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>default</realm-name>
   </login-config>
   
   <security-role>
      <role-name>ttrole</role-name>
   </security-role>

In this example, only users of role "ttrole" can access the servlet and JSP page. Furthermore, only users who are also of role "arole" will cause the SlessLocal bean to be called.

The Java EE environment uses roles for authorization. However in many operating system environments, users are associated with groups. The security-role-mapping provides a link between the concepts of user roles and principals/groups. In a Java EE 5 application server implementation such as the Sun Java System Application Server in the Java EE 5 SDK, you define the security-role-mapping in the sun-application.xml file. Here is an example:

   <sun-application>
     <security-role-mapping>
       <role-name>myrole</role-name>
       <principal-name>myuser</principal-name>
     </security-role-mapping>
     <security-role-mapping>
       <role-name>ttrole</role-name>
       <group-name>ttgroup</group-name>
     </security-role-mapping> 
     <security-role-mapping>
       <role-name>arole</role-name>
       <principal-name>ttuser</principal-name>
     </security-role-mapping>
   </sun-application>

Running the Sample Code

  1. If you haven't already done so, download and install the NetBeans IDE. NetBeans IDE 5.5 with the NetBeans Enterprise Pack 5.5 is available in Java EE 5 SDK Update 2, which you can download from the Java EE Downloads Page.

  2. Download the sample package for the tip and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/webann, where <sample_install_dir> is the directory where you installed the sample package. For example, if you extracted the contents to C:\ on a Windows machine, then your newly created directory should be at C:\webann

  3. Start the NetBeans IDE.

  4. Open the webann project. If you see a "Resolve missing server problem" message, then the application server has not added to the server list in NetBeans. Select Tools > Server Manager to add the server to the server list.

  5. Start the Sun Java System Application Server in NetBeans. You can also start the application server by entering the following command on the command line:
      <appserv_install_dir>/bin/asadmin start-domain domain1

    where <appserv_install_dir> is the directory in which you installed the Sun Java System Application Server.

  6. Create a user. You can do this in the Admin Console (default: http://localhost:4848 ) as follows:
    • Navigate the left panel of the Admin Console:

      Configuration > Security > Realms > file,

    • Click "Manage Users" and then click "New".
    • Enter the following information:
      User Id: ttuser
      Group List: ttgroup
      New Password: ttpassword
      Confirm New Password: ttpassword
    • Click "OK".

    After creating the user, create a second user in the same group by entering the following:

    User Id: ttuser2
    Group List: ttgroup
    New Password: ttpassword
    Confirm New Password: ttpassword
  7. Build the project as follows:
    • Right click the webann node in the Projects window.
    • Select "Clean and Build Project".

    This builds an ear file, web.ear, and puts it in the webann/dist directory.

  8. Deploy the ear file as follows:

    • Right click the webann node in the Projects window.
    • Select "Deploy Project".

    You can also deploy the ear file through the Admin Console as follows:

    • Navigate the left panel of the Admin Console:

           Applications > Enterprise Applications

    • Click "Deploy".
    • Click the "Browse" button to find the ear file.
    • Click OK.

    You can also deploy the ear file by entering the followingcommand on the command line:

       asadmin deploy webann.ear

  9. Start the application by pointing your browser to https://<host>:<port>/webann, where <host> is the host name of your application server, for instance "localhost", and <port> is your HTTPS port, for instance, 8181.

    Depending on your browser, you might see a message stating that there is a problem with the web site's security certificate or web site certified by an unknown authority. That's because this example uses a self-sign certificate. The browser should offer you the option of continuing to the web site to start the application.

    The application will then prompt you to login. Recall that you created two users: ttuser and ttuser2. If you login as ttuser, you should see a response from the application that looks similar to the following:

    Hello, ttuser
    Ejb Message: Hello, World, Sat Jun 30 12:04:46 PDT 2007
    DataSource login timeout: 0

    If you login as ttuser2, then you should see a response similar to the following:

    Hello, ttuser2
    DataSource login timeout: 0

    The difference in the response is due to the roles for each user. The user ttuser has roles "ttrole" and "arole". The user ttuser2 has the role "ttrole", but not the role "arole". In this application, only users that have the role "arole" are authorized to invoke the method SlessLocal.hello(String message), the method that creates the "Hello, World" message.

When you finish the application, you can undeploy it and remove the users you created as follows:

  1. Undeploy the ear through the Admin Console as follows:

    • Navigate the left panel of the Admin Console:

           Applications > Enterprise Applications

    • Choose "webann" and then click "Undeploy".

  2. Remove the user through the Admin Console as follows:

    • Navigate the left panel of the Admin Console:

           Configuration > Security > Realms > file

    • Click "Manage Users".
    • Choose "ttuser" and "ttuser2".
    • Click "Delete".

About the Author

Shing Wai Chan is a member of the Java EE development team at Sun Microsystems. He has been a key contributor in Java EE security for the past few years.

How to Get the Best Performance Out of a Java Persistence Implementation
By Rahul Biswas  

The Java Persistence API, or simply Java Persistence, introduced in the Enterprise JavaBeans (EJB) 3.0 specification (JSR 220), simplifies the development of Java EE applications that use data persistence. Earlier Tech Tips, such as Converting a POJO to a Persistent Entity,Inheritance and the Java Persistence API,and Using Java Persistence With JavaServer Faces Technology, covered various aspects of the Java Persistence API. This tip discusses how to tune the Java Persistence implementation in GlassFish called Toplink Essentials.

The example included in this tip is based on the customer-cmp sample bundled with GlassFish. You can download the samples from the GlassFish Samples page. The tip covers performance tuning for a Java Persistence implementation used in different modes: in-container and out-of container. The tip also uses the Faban framework to demonstrate different performance tuning parameters.

Before discussing the tuning parameters, let's examine in-container and out-of container modes and the Faban framework.

Two Modes of Running a Java Persistence Implementation

You can use Java Persistence implementations that are compliant with JSR-220 in either of two modes: in-container and out-of-container. This is a marked difference between earlier enterprise Java Persistence implementations such as container-managed persistence in EJB 2.1. With EJB 2.1 container-managed persistence a Java Persistence implementation could only run using in-container mode.

In-container mode means that the Java Persistence implementation is used inside of an EJB container. EntityManagers, objects that manage persistence entities, are usually created by the EJB container. Entity managers are typically JTA entity managers. In other words, they participate in transactions controlled by the Java Transaction Architecture (JTA). However, the Java Persistence implementation must support both JTA entity managers and resource-local entity managers, that is, entity managers that participate in transactions not managed by JTA.

In out-of-container mode the Java Persistence implementation is either standalone or runs inside of a web container. The application is responsible for creating it's own entity managers. Transactions are usually resource-local. If the implementation runs standalone, it does not need to support JTA.

The Faban Driver Framework

Faban is an open-source driver framework. It lets developers focus on driver logic implementation so that they can quickly develop performance drivers. Faban takes care of common tasks such as load-generation, output formatting, and the timing of operations. For more about the Faban, see the Faban project page.

Tuning the Sample Application

The customer-cmp sample application interacts with a relational database to store and display information about customer subscriptions to periodicals. The database stores information such as a customer's name and address, as well as the type of periodical to which the customer is subscribed -- that is, magazine, journal, or newspaper. Users can submit requests to the application to display subscription-related information.

This tip focuses on one of the operations supported by the application: finding a customer by his or her ID.

Changing the Cache Size and Number of Connection Pools

Let's examine the impact that specific tuning parameters have on the combined throughput of these operations. Specifically, let's examine the impact of changing the cache size in Toplink Essentials and resetting the number of connections in the connection pool in GlassFish for database calls.

The Toplink Essentials implementation has a default cache size of 1000 per entity. For the purpose of demonstrating the effect of the cache setting, let's look at the transaction rate using the default cache size. Then let's change the cache size to 5000 and compare the results.

To set the cache size, you need to update the persistence.xml file in your project and set the toplink.cache.size.default property as follows:

   <property name="toplink.cache.size.default" value="5000"/>

In this example, there are 20,0000 customer entities in the database.

The cache setting applies to both in-container and out-of-container modes. The connection pool setting, however, is handled differently depending on whether you use in-container or out-of-container mode. For In-container mode, the connection pool setting is done in GlassFish and is controlled by the data-source configuration. In this mode, you can configure the connection pool using the GlassFish admin console as shown below.


Edit Connect Pool

Edit Connect Pool. Click here for a larger image.

For in-container mode, set the number of connections in the connection pool within the container to the number of request processing threads configured in an instance of GlassFish (in this case, 40). This is the maximum number of threads that can be active at any time and thus the maximum number of connections ever needed by Toplink Essentials for database calls.

For out-of-container mode, the connection pool setting is done in the persistence.xml file. The Toplink Essentials implementation has a default connection pool setting of eight connections for both read and write connections. Let's run the application in out-of-container mode for eight users, so set the connection pool value to eight connections.

Results

Running Toplink Essentials using in-container mode produces results similar to the following:

Cache Size Transactions/second
  1000 (default)   1911.493
  5000   3727.253

Running Toplink Essentials using out-of-container mode produces results similar to the following:

Cache Size/
Connection Pool
Transactions/second
  1000/default*   1456.153
  5000/8   6510.0

* The default values are:

toplink.jdbc.read-connections.min = 2
toplink.jdbc.read-connections.max = 2
toplink.jdbc.write-connections.max = 10
toplink.jdbc.write-connections.min = 5

Note that when the default values are used, the connection pool is initialized with the default min setting and can scale to a maximum specified by the default max setting. By setting a connection pool value of 8, there are always be eight connections in the pool.

The system configurations for the tests are as follows:

Sun Fire V880, Solaris 10, 4 CPUs for System under test (SUT).
Sun Fire V880, Solaris 10, 12 CPUs for driver system.

Note that the driver and the SUT are the same system for the out-of-container test. The Driver system and SUT have a point-to-point ethernet connection, which means it has no external network traffic.

Summary

To get the best performance out of your Java Persistence implementation, it's important to understand the tuning parameters provided by the implementation.

The cache setting is an important tuning parameter provided by the Toplink Essentials implementation. Tuning the connection pool setting provided by GlassFish is also important in getting the best performance out of any Java Persistence implementation used in GlassFish.

If you use a Java Persistence implementation outside of the EJB container, the cache setting and connection pool setting again play an important role in the performance of the implementation. However, in this case you set the connection pool value in the persistence.xml file.

There are other parameters that might impact the performance of a Java Persistence implementation. One is the statement cache. This needs to set explicitly for some databases such as an Oracle database. The statement cache is turned on by default in the Java DB database bundled with GlassFish.

In addition, your Java Virtual Machine (JVM)* settings can play an important role in performance tuning. For detailed information on JVM tuning, see the Java Tuning White Paper In running the application for this tip, the JVM options were set to the following values:

  -server -XX:+AggressiveHeap -Xmx2500m -Xms2500m -Xss128k
  -XX:+DisableExplicitGC

* As used in this document, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.

For More Information

For more information about Java Persistence, see The Java Persistence API - A Simpler Programming Model for Entity Persistence and the Java Persistence API FAQ.

For more information about Toplink Essentials, see TopLink Essentials - The Java Persistence API Implementation at GlassFish.

Running the Sample Code

To install and run the sample code that accompanies this tip:

  1. If you haven't already done so, download GlassFish from the GlassFish Community Downloads Page, and install it.

  2. Set the following environment variables:

    • GLASSFISH_HOME. This should point to where you installed GlassFish.
    • ANT_HOME. This should point to where ant is installed. Ant is included in the GlassFish bundle that you downloaded. (In Windows, it's in the lib\ant subdirectory.)
    • JAVA_HOME. This should point to the location of JDK 5.0 on your system

    Add $JAVA_HOME/bin, $ANT_HOME/bin, and $GLASSFISH_HOME/bin to your PATH environment variable.

  3. Download the sample package and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/ttmay2007JPAper, where <sample_install_dir> is the directory in which you installed the sample package. The samples directory below ttmay2007JPAper contains the source files and other support files for the sample.

  4. Change to the samples/bp-project directory and edit the build.properties file as appropriate. For example, if the admin host is remote, change the value of admin.host from the default (localhost) to the appropriate remote host. Also, make sure that the javaee.server.passwordfile location is correct.

  5. Start GlassFish:

      $GLASSFISH_HOME/bin/asadmin start-domain domain1

  6. Change to the samples/javaee5/enterprise/customer-cmp-ear directory and enter the following command:

      ant start-db

  7. Change to the samples/javaee5/enterprise/customer-cmp-ear/setup directory and enter the following commands:

      ant create-db
      ant setup  Â
      ant generate-data
      ant configure-glassfish

  8. To run the benchmark driver in various modes, change to the samples/javaee5/enterprise/customer-cmp-ear/customer-cmp-driver directory and enter the following commands:

      In-container mode, non-optimized: ant run_inc_default
      In-container mode, optimized: ant run_inc_optimized
      Out-of-container mode, non-optimized: ant run_ooc_default
      Out-of-container mode, optimized: ant run_ooc_optimized

    The output of each run is stored in the samples/javaee5/enterprise/customer-cmp-ear/customer-cmp-driver/output/${runid} directory, where ${runid} is the id of each run displayed on the console during the run. To see the results, view the summary.xml file in that directory.

    After the run is finished, you can undo the tuning settings. Change to the samples/javaee5/enterprise/customer-cmp-ear/setup directory and enter the following command:

      ant unconfigure_glassfish.

About the Author

Rahul Biswas is a member of the Java Performance Engineering group at Sun. He is currently involved in the performance improvement of the persistence implementation in GlassFish.

Developers Assistance

Need programming advice on Java EE? Try Developer Expert Assistance

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.