Pages

Saturday, 17 November 2012

Hibernate as Persistence Provider and ORM Solution – Part II


Continues from Part I

Configuring Hibernate Framework

The instance of org.hibernate.cfg.Configuration is used to manage Hibernate configuration that represents an entire set of mappings of an application’s Java types to an SQL database. These mappings are compiled from various XML mapping files or from Java 5 Annotations. The org.hibernate.cfg.Configuration is used to build an immutable org.hibernate.SessionFactory.
Hibernate provides following types of configurations
  1. hibernate.cfg.xml – A standard XML file which contains hibernate configuration and which resides in root of application’s CLASSPATH
  2. hibernate.properties – A Java compliant property file which holds key value pair for different hibernate configuration strings.
Programmatic configuration – This is the manual approach. The configuration can be defined in Java classes.

It is noticeable here that if both hibernate.cfg.xml and hibernate.properties files are provided simultaneously in an application then hibernate.cfg.xml gets precedence over hibernate.properties.


Pros and Cons of Hibernate Framework


Pros

  • Reduces development effort for persisting data from business tier.
  • With help of object relational mapping the database operations on tables can be performed in an object oriented style.
  • It allows caching of persistent objects that can be used for the performance improvement.
  • It is database vendor neutral.
  • Developer is not required to know SQL statements.

Cons

  • For highly data intensive applications, hibernate does not perform up to the mark due to memory issues.
  • Hibernate is suitable only if the database schema is well designed and not very complex.
  • Testing and debugging memory leaks might take a lot of time because the framework does not provide the control to write an optimized query.
  • Sometimes hibernate may generate a vendor specific query in the background that is performance wise very poor.
  • Needs high level of expertise for handling the performance tuning issues.


Using SessionFactory, Session and Transaction objects in an application


If there is single data source to which application needs to connect then only one SessionFactory object is enough for the entire application. However if an application is supposed to be connected to multiple data sources then in that case the number of SessionFactory objects in the application should be equal to the number of data sources. In most of the cases it is the best practice to use single hibernate session for a single request. If we tend to use same session for multiple requests then it means more number of persistent objects will reside in the first level cache which is a memory leak and thus not desired.

Whenever a Servlet receives any request a new thread is assigned to that request and if we follow the session-per-request approach then we will always have a unique session for each thread created against each request.

Now the question is how we can ensure that for each thread there is always a unique session? Simply use ThreadLocal variables to handle Hibernate sessions and that is it. It is noticeable that although a session can span over multiple transactions yet on a given point of time there can not be more than one active transactions as in Hibernate there is no concept of nested transactions. Therefore we can also use ThreadLocal variables to handle Hibernate transactions. Please take a look at the following utility class that does provide this functionality.
import java.sql.SQLException;
import java.util.logging.Logger;
import org.hibernate.Transaction;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
 
public final class HibernateUtil {

   private static final Logger logger  = Logger.getLogger(HibernateUtil.class.getSimpleName());
   private static final ThreadLocal<Session> threadSession =
      new ThreadLocal<Session>();
   private static final ThreadLocal<Transaction> threadTransaction =
      new ThreadLocal<Transaction>();
   private final static SessionFactory sessionFactory;

   static {
      sessionFactory = buildSessionFactory();
   }
    
 
   private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new AnnotationConfiguration()
              .configure()
                    .buildSessionFactory();
        } catch (Throwable ex) {
            logger.warning("Initial SessionFactory creation failed.");
            throw new ExceptionInInitializerError(ex);
        }
   }

   public static Session getCurrentSession() {
      Session s = threadSession.get();
      try {
         if (s == null || !s.isOpen()) {            
            logger.info("Opening new Session for this thread.");            
            s = sessionFactory.openSession();
            threadSession.set(s);
         }
         else {            
               logger.info("Using current session in this thread.");            
         }
      } catch (HibernateException ex) {
         throw new IllegalStateException("unable to open hibernate session",ex);
      }

      return s;
   }

   public static WrappedSession getWrappedSession() {
      return new WrappedSession(getCurrentSession());
      
   }

   public static void closeSession() {
      try {
         final Session s = threadSession.get();
         if (s != null && s.isOpen()) {
            logger.info("Closing Session of this thread.");
            s.close();
         }
      }
      catch (HibernateException ex) {
         logger.warning("Failed to close session of this thread.");
      }
      finally {
         threadSession.set(null);
      }
   }

   public static void beginTransaction() {
      Transaction tx = threadTransaction.get();
      try {
         if (tx != null && !tx.isActive()) {
            tx = null;
            threadTransaction.set(null);
         }
         if (tx == null) {
            
            logger.info("Starting new database transaction in this thread.");       
            tx = getCurrentSession().beginTransaction();
            threadTransaction.set(tx);
         }
         else {
            
            logger.info("Using current database transaction in this thread.");            
         }
      }
      catch (HibernateException ex) {
         throw new IllegalStateException("Failed to start new database transaction in this thread.");
      }
      finally {
         if (threadSession.get() == null || !threadSession.get().isOpen()) {
            getCurrentSession();
         }
      }
   }

   public static void commitTransaction() {
      final Transaction tx = threadTransaction.get();
      try {
         if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack())
         {                            
            logger.info("Flushing session and committing transaction of this thread.");
            Session s = getCurrentSession();
            s.flush();
            tx.commit();
         }
      }
      catch (HibernateException ex) {
         rollbackTransaction();
         logger.warning("Failed to flush session and commit transaction of this thread.");
      }
      finally {
         threadTransaction.set(null);
         closeSession();
      }
   }

   public static void rollbackTransaction() {
      final Transaction tx = threadTransaction.get();
      try {
         if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
            logger.info("Trying to rollback database transaction of this thread.");
            tx.rollback();
         }
      }
      catch (HibernateException ex) {
         logger.warning("Failed to rollback database transaction of this thread.");
      }
      finally {
         threadTransaction.set(null);
         closeSession();
      }
   }
}

Friday, 2 November 2012

Hibernate as Persistence Provider and ORM Solution - I

Introduction

Since the very beginning of Hibernate framework it has been continuously gaining support and popularity. I am therefore very much interested in covering important aspects of Hibernate framework in my current as well as upcoming posts on Java technologies.

Hibernate was started in 2001 by Gavin King as an alternative to using EJB2-style entity beans. It is important to know what persistence actually is before starting our discussion on Hibernate. Persistence is a process of storing the data to some permanent medium and retrieving it back at any point of time even after the application that had created the data ended. The purpose behind this framework was to offer better persistence capabilities by simplifying the complexities and allowing for missing features.

Hibernate is an object-relational mapping (ORM) framework where ORM can be defined as,


A programming method for mapping the objects to the relational model where entities/classes are mapped to tables, instances are mapped to rows and attributes of instances are mapped to columns of table”.

 

Basic Architecture of Hibernate 

 

It is important to note here that the persistent objects synchronize data between application and database layers.

 

Detailed Architecture of Hibernate

 


A Java class mapped to any database table is called an Entity. The instance of an entity becomes a persistent object with help of SessionFactoy which is a singleton instance that implements Factory design pattern. SessionFactory loads hibernate.cfg.xml file and with the help of TransactionFactory and ConnectionProvider implements all the configuration settings on a database.
The Session object is created out of a SessionFactory object and it simply represents a single connection with database. It is also noticeable that a Session can span through multiple transactions where each transaction represents a single atomic unit of work. Hibernate also provides built-in Transaction APIs which abstracts away the application from underlying JDBC or JTA transaction.

SessionFactory

  • A factory for org.hibernate.Session instances.
  • A thread-safe, immutable cache of compiled mappings for a single database.
  • A client of org.hibernate.connection.ConnectionProvider.
  • Optionally maintains a second level cache of data that is reusable between transactions at a process or cluster level.

Session

  • A single-threaded, short-lived object representing a conversation between the application and the persistent store.
  • Wraps a JDBC java.sql.Connection.
  • Factory for org.hibernate.Transaction.
  • Maintains a first level cache of the application’s persistent objects and collections; this cache is used when navigating the object graph or looking up objects by identifier.

Persistent/Attached objects

  • Short-lived, single threaded objects containing persistent state and function.
  • These can be ordinary JavaBeans/POJOs.
  • They are associated with exactly one Session.
  • Once the Session is closed, they will be detached and free to use in any application layer.

Transient/Detached objects

  • Instances of entity classes that are not currently associated with an active Session.

Transaction (org.hibernate.Transaction)

  • An optional, single-threaded, short-lived object used by the application to specify atomic units of work.
  • Although the use of Transaction is optional yet the Transaction demarcation is never optional.
  • It abstracts the application from the underlying JDBC, JTA or CORBA transaction.
  • A Session might span through several transactions.

ConnectionProvider (org.hibernate.connection.ConnectionProvider)

  • It provides pool of JDBC connections.
  • It abstracts the application from underlying javax.sql.DataSource or java.sql.DriverManager.

TransactionFactory (org.hibernate.TransactionFactory)

  • A factory for org.hibernate.Transaction instances.




Saturday, 20 October 2012

Configuring and Launching Sonar Analysis from Jenkins - Part[II]




Configuring Jenkins for Sonar Analysis

1. Click on New Job left menu item. Provide the job name and select “Build a free-style software project” radio button. Now on clicking OK button a screen appears that lets user configure the newly created job as shown below.



2. Provide the project name and description.



3. Set build type as 'Invoke Standalone Sonar Analysis'.



4. Either provide path to project properties file or provide project properties directly in the textarea shown below and save the configuration. (Please refer to the previous post for the sonar project properties)




5. Now run the newly created 'standalone sonar analysis build' by clicking on run icon as depicted under.



6. Once build is completed navigate to its console section to see the complete logs.



Note: If build is run successfully then SUCCESS message will be visible on the bottom of the logs as shown in the below snapshot.


7. Finally go to the sonar server to see the results of the sonar analysis launched by Jenkins CI which is also shown below.




That's it. You have successfully launched your first sonar analysis from the Jenkins CI.




Sunday, 5 August 2012

Configuring and Launching Sonar Analysis from Jenkins - Part[I]



Installing Jenkins


Jenkins can mainly be installed in two different ways. One way is using the native package for the installation and the other one is to deploy the Jenkins war file into a servlet container like tomcat. The Jenkins war file can be downloaded directly from http://mirrors.jenkins-ci.org/war/latest/jenkins.war. For details about Jenkins CI please visit http://jenkins-ci.org/.
Here we will use the second option that is downloading and deploying the Jenkins war file into a servlet container. We will be using Tomcat as a servlet container where the downloaded Jenkins war file will be deployed.
Also remember that we need to define JENKINS_HOME environment variable that points to the location from where Jenkins loads all of its configuration.
It is better to define this environment variable on servlet container level by placing the following line in $CATALINA_HOME/config/context.xml so that it will remain there even if a newer version of Jenkins is deployed on Tomcat server.
<Environment name="JENKINS_HOME" value="/home/atif/Jenkins/" type="java.lang.String"/>


Having added the above line in $CATALINA_HOME/config/context.xml and deployed Jenkins war file; restart the tomcat server. Now the Jenkins server should be up and running as depicted under.
snapshot 1
In the above snapshot a message warns us that our Tomcat is not UTF-8 compatible. The link Tomcat i18n on the right side opens a help page on the Jenkins web site, where the solution for the above problem is mentioned.

In the $CATALINA_HOME/config/server.xml file look for the section Connector and insert the following attribute: URIEncoding=”UTF-8″. This is how it looks in my file:
snapshot 2
 
The second warning informs us that a newer version of Jenkins war file is available for download. Simply download it from the link appearing in the warning message and redeploy the updated Jenkins war file.

Installing Sonar Plugin for Jenkins

First access the Jenkins server from the browser and navigate to Manage Jenkins → Manage Plugins screen as shown below.

snapshot 3
Now select the sonar plugin and click on 'Install without restart' button as shown below.
snapshot 4
 
The sonar plugin installation will take some time and once it is installed the installation success message will appear on the UI which is shown in below snapshot.

snapshot 5

Installing and Running Sonar Server

 

Introduction to Sonar

It is an open source platform to continuously analyse and measure code quality. It helps decide the necessary measures that should be taken for the improvement of code quality by focusing the following seven areas that are crucial in deciding the quality of code. 
 

 


For more details please visit http://www.sonarsource.org/


Installing Sonar

Download the latest version of sonar zip file from http://www.sonarsource.org/downloads/ and unzip this file. As currently the latest version is 3.1.1 therefore we will download zip file for the version is 3.1.1. On unzipping this zip file a sonar-3.1.3 directory is created.

In this directory, go to the \conf sub-directory and edit the sonar.properties file. Here, the credentials for a sonar user are already defined:

sonar.jdbc.username:                     sonar
sonar.jdbc.password:                      sonar

Note: We need to change the above username and password properties if we have different database credentials.
 
We will look at the section dedicated to MySQL database to define the access to our MySQL database:
sonar.jdbc.url: jdbc:mysql://localhost:3306/sonar?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true                       
sonar.jdbc.driverClassName: com.mysql.jdbc.Driver

sonar.jdbc.validationQuery:  select 1

It is noticeable here that the sonar database should already be created before deploying the sonar web-application to the Tomcat server.
  
And that’s all for the Sonar configuration.

Now, we need to make sure that mysql-connector-java-5.1.18.jar exists in \extensions\jdbc-driver\mysql and if it does not exist then we need to copy it to that location.


Finally build the sonar.war file that we will use to deploy Sonar in Tomcat. But first, it will be better to download the desired Sonar plugins from http://docs.codehaus.org/display/SONAR/Plugin+Library and put them into the Sonar \extensions\plugins directory to avoid restarting sonar server
for loading the plugins.

It is very important to know that for sonar version 3.1.1the SonarJ plugin prevents the sonar server from starting therefore we should use Sonargraph plugin instead. Please see comments on SONARPLUGINS-1434

Now run the build-war.bat file for windows or build-war.sh file for linux or Mac located in the \war directory and soon you will have the sonar.war file created.

Now deploy the generated war file into the Tomcat server. The sonar server should be up and running as depicted under.



Note that the default username and password for sonar administrator user is admin/admin.

Analysing Projects with Sonar Runner

First download Sonar Runner zip file from http://docs.codehaus.org/display/SONAR/Installing+and+Configuring+Sonar+Runner. Unzip the file and open sonar-runner.properties file in the /conf directory. Now set the global database and sonar server properties for the sonar runner.


#----- Default Sonar server
sonar.host.url=http://localhost:8080/sonar

#----- MySQL
sonar.jdbc.url=jdbc:mysql://localhost:3306/sonar?useUnicode=true&amp;characterEncoding=utf8
sonar.jdbc.driver=com.mysql.jdbc.Driver

#----- Global database settings
sonar.jdbc.username=sonar
sonar.jdbc.password=sonar

Note: We need to change the above username and password properties if we have different database credentials.

Next add an environment variable SONAR_RUNNER_HOME to point to the root directory of the sonar runner and also add  SONAR_RUNNER_HOME/bin to PATH variable.

Now go to the root directory of the project that should be analysed with sonar and add a sonar-project.properties file there that should contain the following properties.


# required metadata
sonar.projectKey=h:TTSProject
sonar.projectName=TTSProject
sonar.projectVersion=1.0

# path to source directories (required)
sources=src

# path to test source directories (optional)
# tests=testDir1,testDir2

# path to project binaries (optional), for example directory of Java bytecode
binaries=build

# optional comma-separated list of paths to libraries. Only path to JAR file and path to directory of classes are supported.
# libraries=path/to/library.jar,path/to/classes/dir


# Uncomment this line to analyse a project which is not a java project.
# The value of the property must be the key of the language.
# sonar.language=cobol

# Additional parameters
sonar.scm.url=scm:svn:file://localhost:8080/sonar

Note that the sonar.scm.url property is needed when sonar scm activity plugin is added to the sonar application. The format for the sonar.scm.url is predefined. Please visit for details http://maven.apache.org/scm/scm-url-format.html.

scm:<scm_provider><delimiter><provider_specific_part> 


Finally run sonar-runner command from the root directory of the project where sonar-project.properties file was added. That's it. Following snapshot depicts the results of our first sonar analysis.