Jan 23, 2013

You're IT: Hibernate Case in Select Clause strange behavior

You're IT: Hibernate Case in Select Clause strange behavior: It seems there is some strange behavior when using the CASE WHEN THEN ELSE END in the select clause. When using It results in  java.lang....

Jan 14, 2013

Demystifying “Loading JDBC Driver”


Recently while interacting with newbies or say IT aspirants when being asked about simple JDBC questions most of the people were at sea. Question was simple
“While getting JDBC connection in java application what we do is first we call Class.forname(“<driver-name”) and then we call DriverManager.getConnection with appropriate arguments. We do not get any value from Class.forname and return it to DriverManager so how this works.
Class.forName("driver-name");
DriverManager.getConnection(url, user, password);

Most of the people those who answered simply said it will load JDBC driver. Next question was “What does that mean”. Long pause and then again “Will load the driver” J
So now let’s see what happens when we call Class.forname on JDBC driver for MySQL db.
Class.forName("com.mysql.jdbc.Driver");

Following is code snippet from MySQL driver class.
So when we call Class.forname(“com.mysql.jdbc.Driver”) static block of this class will be called
static {
       try {
              java.sql.DriverManager.registerDriver(new Driver());
       }
       catch (java.sql.SQLException E) {
              throw new RuntimeException("Can't register driver!");
       }
       if (DEBUG) {
              Debug.trace("ALL");
       }
}

Looking at the code we understand that Class.forname will call registerDriver method of DriverManager class and will pass instance of Driver class for MySQL to DriverManager. When DriverManger.registerDriver is called it will check for null and if it is not null then it will add this driver in list of registered drivers.
public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException
{     
       /* Register the driver if it has not already been added to our list */
       if(driver != null) {
              registeredDrivers.addIfAbsent(new DriverInfo(driver));        
       }
       else {
              // This is for compatibility with the original DriverManager
              throw new NullPointerException();              
       }
       println("registerDriver: " + driver);
}

When getConnection(url, user, password) is called it will internally call getConnection(url, driverinfo, classLoaded) which will iterate through registered drivers and call connect method on Driver for which which will create and return connection.
for(DriverInfo aDriver : registeredDrivers)
{                         
       // If the caller does not have permission to load the driver then skip it.
       if(isDriverAllowed(aDriver.driver, callerCL))
       {
              try {
                     println("    trying " + aDriver.driver.getClass().getName());
                     Connection con = aDriver.driver.connect(url, info);
                     if (con != null) {
                           // Success!
                           println("getConnection returning " + aDriver.driver.getClass().getName());
                           return (con);                                         
                     }                                       
              } catch (SQLException ex) {
                     if (reason == null) {
                           reason = ex;                                          
                     }                                       
              }                                
       }
       else {
              println("    skipping: " + aDriver.getClass().getName());                               
       }                         
}

So this is how all happens…Happy coding.. J

Jan 13, 2013

Formatting JUnit Results with Ant


One of the best practice for developing application is Test Driven Development. Common most tool/api we use in Java for unit testing is JUnit and for automation we use is Ant. Ant task for JUnit supports four result format.

  • ·         xml
  • ·         pPlain
  • ·         brief
  • ·         failure
Details about these formats can be found at JUnit task document. But at times we need to get unit test results in format other than default format. In my case I wanted to store these results in csv/xls format to keep track of results that have passed/failed/thrown error during development. So we created our own format by implementing org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter. For implementing this interface we need to have following jars in classpath
·         ant.jar
·         ant-junit.jar
·         junit-x.y.jar (Where x and y are version and subversion of jar)
So we create a java project in Eclipse and add these jars in build path and create following class in java project.
package com.customization.ant.junit.formatter;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Vector;

import junit.framework.AssertionFailedError;
import junit.framework.Test;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitVersionHelper;

import com.customization.ant.junit.bean.UnitTestBean;

public class XLSFormatter implements JUnitResultFormatter{
       private enum TestStatus {PASS,FAIL,ERROR};

       boolean testsuccess = true;
       boolean isError = false;
       private OutputStream ostrm;
       private List<UnitTestBean> beanlist = new Vector<UnitTestBean>(); 
       @Override
       public void addError(Test test, Throwable t) {
              testsuccess=false;
              isError = true;
       }

       @Override
       public void addFailure(Test t, AssertionFailedError e) {
              testsuccess=false;
              System.out.println("Adding failure");
       }

       @Override
       public void endTest(Test test) {
              String caseName = JUnitVersionHelper.getTestCaseName(test);
              UnitTestBean bean = new UnitTestBean();
              bean.setCaseName(caseName);
              bean.setSuccessful(testsuccess);
              beanlist.add(bean);       
       }

       @Override
       public void startTest(Test test) {
              testsuccess = true;
              isError = false;
       }

       @Override
       public void endTestSuite(JUnitTest test) throws BuildException {
              StringBuffer sbuff = new StringBuffer();
              sbuff.append("TestCase Name,Status\n");
              for(UnitTestBean bean:beanlist)
              {
                     sbuff.append(bean.getCaseName()).append(",").append(bean.isSuccessful()?TestStatus.PASS:
                           isError?TestStatus.ERROR:TestStatus.FAIL).append("\n");
              }
              try
              {
                     ostrm.write(sbuff.toString().getBytes());
                     ostrm.flush();
                     ostrm.close();
              } catch (IOException e) {
                     e.printStackTrace();
              }            
       }

       @Override
       public void setOutput(OutputStream ostrm) {
              this.ostrm = ostrm;
       }

       @Override
       public void setSystemError(String arg0) {
              isError=true;
       }

       @Override
       public void setSystemOutput(String arg0) {
       }

       @Override
       public void startTestSuite(JUnitTest test) throws BuildException {
       }
}

Let’s understand the code now. We will define following class level variables to store status of test cases.
       private enum TestStatus {PASS,FAIL,ERROR};
       boolean testsuccess = true;
       boolean isError = false;
testsuccess will be set to true if test case is executed successfully. If test case fails then addFailure(Test t, AssertionFailedError e) will be called and we will set variable testsuccess to false. Default value of isError will be set to false and if any Exception/Error occurs while executing test case then addError(Test test, Throwable t) will be called and in this method we will set isError to true.
When we implement org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter interface we need to implement following methods.
  •  addError(Test, Throwable): As explained this method will be called when any error occurs while executing test case. We will set isError to true if/when this method is called.
  • addFailure(Test, AssertionFailedError): As explained this method will be called when any test case fails. We will set testsuccess to false if/when this method is called.
  • endTest(Test): This method will be called at the end of every test. We will use this method to set the value of testcase name and status of this test case (i.e. Pass/Fail/Error) and add it in a Collection (Vector in our case)
  • endTestSuite(JUnitTest): This method will be called at the end of Test suite. We will use this method to write result of all tests in csv file.
  • setOutput(OutputStream): Output stream as defined in ant task will be passed as an argument. We will store this as handler to local variable to use it later for writing our test results.
  •  setSystemError(String): This method is not used in our case.
  •  setSystemOutput(String): We are not using this method either.
  •  startTest(Test): Not this one too…
  •  startTestSuite(JUnitTest): Ok…not even this one J

Now compile this class and export it as a jar. Add this jar in project where we want to run test cases. In JUnit ant task of build file add following as formatter. (Following is simplest of options to tell the build file to use this new class for formatting results)
Now compile this class and export it as a jar. Add this jar in project where we want to run test cases. In JUnit ant task of build file add following as formatter. (Following is simplest of options to tell the build file to use this new class for formatting results)
<formatter classname="com.customization.ant.junit.formatter.XLSFormatter" extension=".csv" />

Here we are using a very simple JUnit test case for employee registration. Where method accepts data in form of a bean and registers employee. If passed bean is null or values passed in bean are invalid then it will return false and if bean is valid then employee will be registered and method will return true. So following will be test class.
package com.sampleapp.service.test;

import org.junit.Test;

import com.sampleapp.service.EmployeeRegistrationService;
import com.sampleapp.vo.EmployeeBean;

import junit.framework.TestCase;

public class EmployeeServiceTest extends TestCase
{
       EmployeeBean empBean=null;
       EmployeeRegistrationService svc = new EmployeeRegistrationService();
       @Override
       protected void setUp() throws Exception {
              System.out.println(getName());
              super.setUp();
       }
       @Test
       public void testForNullEmployee()
       {
              boolean retval = svc.registerEmployee(null);
              assertFalse("Registered Null employee",retval);
       }
       @Test
       public void testForValidEmployee()
       {
              empBean = new EmployeeBean();
              boolean retval = svc.registerEmployee(empBean);
              assertTrue("Not able to registered valid employee",retval);
       }
}

When we will run this test case following will be output on console
Apache Ant(TM) version 1.8.3 compiled on February 26 2012
Buildfile: E:\softwares\java\workspaces\keyur\Blogs\TestDrivenDevelopment\src\build.xml
parsing buildfile E:\softwares\java\workspaces\keyur\Blogs\TestDrivenDevelopment\src\build.xml with URI = file:/E:/softwares/java/workspaces/keyur/Blogs/TestDrivenDevelopment/src/build.xml
Project base dir set to: E:\softwares\java\workspaces\keyur\Blogs\TestDrivenDevelopment\src
parsing buildfile jar:file:/E:/softwares/java/eclipse-jee-juno-SR1-win32/eclipse/plugins/org.apache.ant_1.8.3.v20120321-1730/lib/ant.jar!/org/apache/tools/ant/antlib.xml with URI = jar:file:/E:/softwares/java/eclipse-jee-juno-SR1-win32/eclipse/plugins/org.apache.ant_1.8.3.v20120321-1730/lib/ant.jar!/org/apache/tools/ant/antlib.xml from a zip file
     [echo] Testing
    [junit]
    [junit]
BUILD SUCCESSFUL
Total time: 287 milliseconds

And following will be the file generated









So this generated data was stored in following format to track results of each build.

















So happy coding.