Spring Hibernate End to End Integration using Maven, Spring MVC, JSP, Oracle11g : A Step by Step Guide

This post aims at giving a start-up point while you begin understanding the Spring-Hibernate integration and would like to start trying it out using a practical implementation  like me. I am using Maven 3, Oracle11g (with a set-up guide including creating a user and a table) , Spring 3.0, Hibernate 3.6 and STS as the development IDE.

The agenda of the post is:

1. Setup DB Layer (Oracle11g)
2. Creating a Maven Project and adding Hibernate Layer
3. Spring Hibernate Integration including Spring MVC

Setup DB Layer (Oracle11g)

To begin with, If you don’t have Oracle already Installed or you need some reference setting up a User or a Table, Visit this Blog Post. We will be using the same table and DB url mentioned in this post to connect it using Spring and Hibernate.

We have used the following Script to generate an “orders” table to connect with.

create table orders (
order_id   number primary key,
order_dt   date,
order_type varchar2(50),
customer_name varchar2(50)
)

Once we are ready with our database and aquire the connection URL, we can move to adding the middleware.

Creating a Maven Project and adding Hibernate Layer

Step 1. Setup Maven (refer http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html)
If have maven already installed, skip this step.

Step 2. Go to Eclipse/STS, Create a new maven Project as:
New -> Other -> Type maven and select New Maven Project
Check “Select a Simple Project”, Click Next
Enter Group Id:com.codeyard
Artifact Id: ordermanager
packaging: war
Name: HelloHibernate
Finish

Step 3. Add hibernate and Oracle driver dependencies to your pom.xml so that it looks like:

<project xmlns="<a href="http://maven.apache.org/POM/4.0.0">http://maven.apache.org/POM/4.0.0</a>" xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>"
xsi:schemaLocation="<a href="http://maven.apache.org/POM/4.0.0">http://maven.apache.org/POM/4.0.0</a> <a href="http://maven.apache.org/xsd/maven-4.0.0.xsd">http://maven.apache.org/xsd/maven-4.0.0.xsd</a>">
<modelVersion>4.0.0</modelVersion>
<groupId>com.codeyard</groupId>
<artifactId>ordermanager</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>HelloHibernate</name>
<dependencies>
<!-- ORACLE JDBC driver, need install yourself -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0</version>
</dependency>

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.6.3.Final</version>
</dependency>
</dependencies>
</project>

I got the following error while adding ojdbc6.jar dependency into my POM:
24/7/12 11:57:05 AM IST: Missing artifact com.oracle:ojdbc6:jar:11.2.0:compile
The POM for com.oracle:ojdbc6:jar:11.2.0 is missing, no dependency information available
Failed to execute goal on project Maven: Could not resolve dependencies … Could not find artifact com.oracle:ojdbc6:jar ….

I could only resolved it by manually installing a copy of the jar in the local repository as:
To manually deploy the Oracle JDBC driver to your local repository type the following:

mvn install:install-file -Dfile={ORACLE_HOME}/jdbc/lib/ojdbc6.jar -Dpackaging=jar\
-DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0
where {ORACLE_HOME} is the path to the Oracle Database installation.

OR

Download ojdbc6.jar from Oracle website, place it on your local machine and type the following:

mvn install:install-file -Dfile=C:/jdbc6.jar -Dpackaging=jar\
-DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0

If anyone could do it in a better way, please share.(uploading the jar into a central repo like Nexus and refering it from there is another workaround).

Step 4. Create a class for Order in package  com.codeyard.order named Order.java src/main/resources/com/codeyard/order

 package com.codeyard.order;

 import java.util.Date;

 public class Order implements java.io.Serializable{

 private static final long serialVersionUID = 1L;

 private int orderId;
 private String OrderType;
 private String customerName;
 private Date OrderDate;

 public Order() {
 }

 public Order(int orderId, String OrderType, String customerName, Date OrderDate) {
     this.setOrderId(orderId);
     this.setOrderType(OrderType);
     this.setCustomerName(customerName);
     this.setOrderDate(OrderDate);
 }

 public int getOrderId() {
     return orderId;
 }

 public void setOrderId(int orderId) {
 this.orderId = orderId;
 }

 public String getOrderType() {
     return OrderType;
 }

 public void setOrderType(String orderType) {
     OrderType = orderType;
 }

 public String getCustomerName() {
     return customerName;
 }

 public void setCustomerName(String customerName) {
     this.customerName = customerName;
 }

 public Date getOrderDate() {
     return OrderDate;
 }

 public void setOrderDate(Date orderDate) {
     OrderDate = orderDate;
 }

 }
 

Step 5. Create a mapping file for hibernate to map your java object to DB entity.
src/main/resources/com/codeyard/order/order.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"<a href="http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd</a>">
<hibernate-mapping>
<class name="com.codeyard.order.Order" table="ORDERS">
<id name="orderId" type="int">
    <column name="ORDER_ID" precision="5" scale="0" />
<generator />
</id>
<property name="OrderType" type="string">
    <column name="ORDER_TYPE" length="20" not-null="true" />
</property>
<property name="customerName" type="string">
    <column name="CUSTOMER_NAME" length="20" not-null="true" />
</property>
<property name="OrderDate" type="date">
    <column name="ORDER_DT" length="7" not-null="true" />
</property>
</class>
</hibernate-mapping>

Step 6. Add hibernate.cfg.xml under src/main/recources as:


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory>
 <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
 <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:P24</property>
 <property name="hibernate.connection.username">testconn</property>
 <property name="hibernate.connection.password">testconn</property>
 <property name="hibernate.default_schema">testconn</property>
 <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
 <property name="show_sql">true</property>

 <!-- add mapping to *.hbm.xml file here -->
 <mapping resource="com/codeyard/order/order.hbm.xml"></mapping>
 <!-- <mapping class="com.codeyard.model.AdvanceOrder" /> -->
</session-factory>
</hibernate-configuration>

Step 7. Create a test class to test if you are able to insert data in order table.

I am using junit4 and for that you need to add the following dependency in pom.xml

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>

Add a java test case in the src/test/java/com/codeyard/hibernate package.

package com.codeyard.hibernate;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.codeyard.order.Order;

public class OrderTest {
SessionFactory sessionFactory;

@Before
public void init() {
try {
  sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
  System.err.println("Failed to create session factory." + ex);
  throw new ExceptionInInitializerError(ex);
}
}

@After
public void after() {
  sessionFactory.close();
}

@Test
public void testOrderCreation(){

  Session session = sessionFactory.openSession();

  session.beginTransaction();
  Order order = new Order();

  order.setOrderId(1);
  order.setOrderDate(new Date());
  order.setCustomerName("Richa");
  order.setOrderType("Small");

  session.save(order);
  session.getTransaction().commit();

}

}

Running this testcase results in the following error on console:

Failed to create session factory.org.hibernate.HibernateException: Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]

To resolve this, I added the following dependency of java assist:
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
</dependency>

Rerun the test case and you should see the following message on console :

Hibernate: insert into testconn.ORDERS (ORDER_TYPE, CUSTOMER_NAME, ORDER_DT, ORDER_ID) values (?, ?, ?, ?)
Row added

DOWNLOAD SOURCE CODE.ZIP
———————————————————————————-

Now open Sql Developer ad refresh the table, you should see the newly added data through test case in the table.
.

Spring MVC and Hibernate

Now, we make this project a little advance by having Spring in place and integrating Hibernate to it.

Step1. Add the following Spring and ORM Dependencies in your POM.xml for spring-hibernate integration.

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.0.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.0.RELEASE</version>
</dependency>

Step 2.  Add a separate AdvanceOrder.java class. we shall map this class in package com.codeyard.model to the same ORDERS Table used previously. We will do the mapping with the help of Spring annotations and will not require any .hbm.xml mapping file anymore.


package com.codeyard.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;

@Entity
@Table(name = "ORDERS")
public class AdvanceOrder {

@Id
 @SequenceGenerator(name = "OrderSequence", sequenceName = "ORDER_SEQ", allocationSize = 5, initialValue = 1)
 @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "OrderSequence")
 @Column(name = "ORDER_ID")
 private int orderId;

 @Column(name = "ORDER_TYPE")
 private String orderType;

 @Column(name = "CUSTOMER_NAME")
 private String customerName;

 @Column(name = "ORDER_DT")
 private Date orderDate;

 public int getOrderId() {
 return orderId;
 }

public void setOrderId(int orderId) {
 this.orderId = orderId;
 }

public String getOrderType() {
 return orderType;
 }

public void setOrderType(String orderType) {
 this.orderType = orderType;
 }

public String getCustomerName() {
 return customerName;
 }

public void setCustomerName(String customerName) {
 this.customerName = customerName;
 }

public Date getOrderDate() {
 return orderDate;
 }

public void setOrderDate(Date orderDate) {
 this.orderDate = orderDate;
 }

}

Uncomment the entry for AdvanceOrder mapping in hibernate.cfg.xml: <mapping />

Step 3.  Add DAO Layer by introducing OrderDAO interface and corresponding OrderImpl class in com.codeyard.dao package as:

OrderDAO.java

package com.codeyard.dao;
import java.util.List;
import com.codeyard.model.AdvanceOrder;

public interface OrderDao {

   public void createOrder(AdvanceOrder order);
   public List<AdvanceOrder> getAllOrders();
   public void deleteOrder(Integer id);
}

OrderImpl.java

package com.codeyard.dao;

import java.util.List;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.codeyard.model.AdvanceOrder;

@Repository
public class OrderImpl implements OrderDao {

@Autowired
 private SessionFactory sessionFactory;

public void createOrder(AdvanceOrder order) {
 sessionFactory.getCurrentSession().save(order);

}

public List<AdvanceOrder> getAllOrders() {
 return sessionFactory.getCurrentSession().createQuery("from AdvanceOrder").list();
 }

public void deleteOrder(Integer id) {
 AdvanceOrder order = (AdvanceOrder) sessionFactory.getCurrentSession()
 .load(AdvanceOrder.class, id);
 if (null != order) {
 sessionFactory.getCurrentSession().delete(order);
 }

}

}

Step 4. Add service layer by introducing OrderService.java and corresponding OrderServiceImpl.java in com.codeyard.service package as:

OrderService.java


package com.codeyard.service;
import java.util.List;
import com.codeyard.model.AdvanceOrder;

public interface OrderService {

  public void createOrder(AdvanceOrder contact);
  public List<AdvanceOrder> getAllOrders();
  public void deleteOrder(Integer id);

}

OrderServiceImpl.java

package com.codeyard.service;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.codeyard.dao.OrderDao;
import com.codeyard.model.AdvanceOrder;

@Service
public class OrderServiceImpl implements OrderService {

@Autowired
 private OrderDao orderDAO;

@Transactional
 public void createOrder(AdvanceOrder contact) {
   orderDAO.createOrder(contact);
 }

@Transactional
 public List<AdvanceOrder> getAllOrders() {
   return orderDAO.getAllOrders();
 }

@Transactional
 public void deleteOrder(Integer id) {
   orderDAO.deleteOrder(id);
 }

}

crete a sequecne in Oracle by running the following command using SQL Developer:
create sequence ORDER_SEQ start with 1 INCREMENT BY 2;
Step 5.Add Spring MVC and some more Dependencies.

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.0.0.RELEASE</version>
</dependency>

<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>20030825.184428</version>
</dependency>

<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>20030825.183949</version>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>

<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>

Step 6.  Create OrdersController.java in com.codeyard.controller to entertain your http requests.


package com.codeyard.controller;

import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.codeyard.model.AdvanceOrder;
import com.codeyard.service.OrderService;

@Controller
@RequestMapping("/orders")
public class OrdersController {
 @Autowired
 private OrderService orderService;

 @RequestMapping(value = "/list", method = RequestMethod.GET)
 public String listContacts(Map<String, Object> map) {
    map.put("order", new AdvanceOrder());
    map.put("orderList", orderService.getAllOrders());
    return "order";
 }

 @RequestMapping(value = "/save", method = RequestMethod.POST)
 public String addContact(@ModelAttribute("order") AdvanceOrder order, BindingResult result) {
    orderService.createOrder(order);
    return "redirect:/orders/list";
 }

 @RequestMapping("/delete/{orderId}")
 public String deleteContact(@PathVariable("orderId") Integer orderId) {
    orderService.deleteOrder(orderId);
    return "redirect:/orders/list";
 }
}

Step 7.Add View Layer.As you can see in the above step, we have used the views and model passed along with the view. We need to have appropriate view (jsp) and view resolver in the spring context file. Our WEB-INF/web.xml looks like:


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 id="WebApp_ID" version="2.5">
 <display-name>OrderManager</display-name>
 <welcome-file-list>
<welcome-file>list.html</welcome-file>
 </welcome-file-list>
 <servlet>
<servlet-name>codeyard</servlet-name>
 <servlet-class>
org.springframework.web.servlet.DispatcherServlet
 </servlet-class>
<load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
<servlet-name>codeyard</servlet-name>
<url-pattern>/</url-pattern>
 </servlet-mapping>
</web-app>

We have used the servlet name as codeyard, Spring will look for the context file named codeyard-context.xml under WEB-INF folder which in this case, looks like:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang"
 xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
 http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
 http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<context:annotation-config />
 <context:component-scan base-package="com.codeyard" />

 <bean id="jspViewResolver"
 class="org.springframework.web.servlet.view.InternalResourceViewResolver">
 <property name="viewClass"
 value="org.springframework.web.servlet.view.JstlView" />
 <property name="prefix" value="/WEB-INF/jsp/" />
 <property name="suffix" value=".jsp" />
 </bean>

<bean id="messageSource"
 class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
 <property name="basename" value="classpath:messages" />
 <property name="defaultEncoding" value="UTF-8" />
 </bean>
 <bean id="propertyConfigurer"
 class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
 p:location="/WEB-INF/jdbc.properties" />

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
 destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
 p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />

 <bean id="sessionFactory"
 class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
 <property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
 </property>
 <property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
 </property>
 <property name="hibernateProperties">
 <props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
 </props>
 </property>
 </bean>

<tx:annotation-driven />

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
 <property name="sessionFactory" ref="sessionFactory" />
 </bean>
</beans>

you can see, we have used reference to jdbc properties file for obtaining DB connections, here is our jdbc.properties file lying under WEB-INF folder

jdbc.driverClassName= oracle.jdbc.driver.OracleDriver
jdbc.dialect=org.hibernate.dialect.Oracle10gDialect
jdbc.databaseurl=jdbc:oracle:thin:@localhost:1521:P24
jdbc.username=testconn
jdbc.password=testconn

We can get rid of the connection related attributes in hibernate.cfg.xml as we can fetch then using properties file now. Add order.jsp.

WEB-INF -> jsp -> order.jsp

<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
 <title>Spring Hibernate Sample Orders</title>
</head>
<body>

<h2>Log Order Details</h2>

<form:form method="post" action="save.html" commandName="order">

<table>
 <tr>
    <td><form:label path="OrderType">Order Type</form:label></td>
    <td><form:input path="OrderType" /></td>
 </tr>
 <tr>
    <td><form:label path="customerName">Customer Name</form:label></td>
    <td><form:input path="customerName" /></td>
 </tr>
 <tr>
    <td><form:label path="orderDate">Order Data</form:label></td>
    <td><form:input path="orderDate" /></td>
 </tr>

<tr>
 <td colspan="2">
   <input type="submit" value="Add Order"/>
 </td>
 </tr>
</table>
</form:form>

<h3>Order History</h3>
<c:if test="${!empty orderList}">
<table>
  <th>Customer Name</td>
  <th>Order Date</td>
  <th>Order Date</td>
<c:forEach items="${orderList}" var="order">
 <tr>
    <td>${order.customerName}</td>
    <td>${order.orderDate}</td>
    <td>${order.orderType}</td>
    <td><a href="delete/${order.orderId}">delete</a></td>
 </tr>
</c:forEach>
</table>
</c:if>

</body>
</html>

Step 8. run mvn clean install from your project’s directory in command prompt. It should results in build success. Copy the ordermanager-0.0.1-SNAPSHOT.war in your tomcat/webapps directory, start the server.

use the url as http://localhost:8080/contextpath/urlpattern/path mentioned in controller

eg: http://localhost:8080/ordermanager-0.0.1-SNAPSHOT/orders/list.

and try the application..  DOWNLOAD SOURCE PART 2.ZIP

Enable JDK 1.8 Tomcat 8 in Eclipse

In order to run Tomcat 8 within Eclipse, following steps worked . ( I tried with Eclipse Luna but it did NOT work for me )

  1. Download Eclipse JavaEEKepler (http://www.eclipse.org/downloads/packages/release/Kepler/SR2)
  2. Download theadapters built for WTP  http://www.eclipse.org/downloads/download.php?file=/webtools/downloads/drops/R3.6.0/S-3.6.0M7-20140505163128/wtp4x-S-3.6.0M7-20140505163128.zip.
  3. Unzip both.
  4. Add (Replace clashes) the corresponding items from features and plugin folders from WTP downloaded (in step 2.) to the corresponding folder in Eclipse Kepler (downloaded in step 1.)
  5. Start eclipse .Go to preference -> Server -> Runtime Environment and add Apache Tomcat v8.0

point5Press Next, select location on the drive (i.e. c:\apachetomcat) for Tomcat installation directory. Make sure that the directory exist.

6. Then press ‘Download and Install’ button, accept terms and point to your installation directory (i.e. c:\apachetomcat) and press OK button

7. Download Jdk. 1.8 and SET JAVA_HOME accordingly.

8. Go to Eclipse Market Place and Install “Mongrel”

mongrel

Restart Eclipse Go to Windows -> Preferences -> Mongrel and point to your tomcat 8 directory (you may choose Tomcat 7.x from radio button)

configure_mongrel

Flex and QTP: Enabling automation and recognizing Flex custom components using delegates

In order to initiate automation on a flex based application, following are the set of software versions that have been used to successfully recognize most of the flex components.
  • Windows 7 (32 bit OS)
  • FlashPlayer 11 (flashplayer_11_ax_debug)
  • Flex 3.6 based application
  • QTP 11 having Flex 4.6 plugin installed

First, We need to have following jars included in your library path for enabling automation via QTP:

  •   automation.swc, automation_agent.swc, automation_dmv.swc, qtp.swc
  •   automation_rb.swc, automation_agent_rb.swc (_rb files supports localization)

If using Maven, these QTP automation related libraries can be downloaded and  installed in the local repository as follows:

mvn install: install-file -DgroupId=com.adobe.flex.framework -DartifactId=automation -Dversion=3.6.0 -Dpackaging=swc -Dfile=automation.swc

Likewise, other libraries can also be installed in maven local repository. Also,  they can be uploaded/installed on external repo like nexus for universal use.

The respective dependencies can be added in desired POM file (usually parent POM or a separate one where you plan to write delegates later)

<dependency>
<groupId>com.adobe.flex.framework</groupId>
<artifactId>automation</artifactId>
<version>3.6.0</version>
<type>swc</type>
<scope>internal</scope>
</dependency>

Once you inject all dependencies,  run mvn clean install,  it would create the target .swf with automation dependencies. As a result, the size of the swf file would be bigger than the original swf by about 1000kB. That is an indication that your flex application is automation enabled.

Now, when you try to hover QTP object spy over your flex application, instead of showing “Win Object”, it will successfully show “Flex Application -> Flex Canvas” etc.

Moving Further, QTP by default  recognizes standard flex components only ( Components mentioned in TEAFlex.xml in QTP installation directory) .

In order to recognize the custom components that are developed by extending standard Flex components or a UIComponent,  it is necessary to write delegates.

A definition of delegate class I could derive by understanding it, is as follows:

“A delegate is a facilitator class, if registered with your “unidentified” flex custom component and when inherited by a related automationImpl class, can return its each child as some Automation Object.”

Following is a sample delegate class, which is written over an un-recognized custom flex component “MyCustomFlexComp”.

package test.delegates
{
 import test.components.MyCustomFlexComp;
 import flash.display.DisplayObject;
 import flash.events.*;
 import mx.automation.Automation;
 import mx.automation.IAutomationManager;
 import mx.automation.IAutomationObject;
 import mx.automation.IAutomationObjectHelper;
 import mx.automation.delegates.core.UIComponentAutomationImpl;
 import mx.automation.events.AutomationRecordEvent;
 import mx.events.*;

[Mixin]
public class MyCustomFlexCompDelegate extends UIComponentAutomationImpl
 // Check what MyCustomFlexComp is extending.
 // Use UIComponentAutomationImpl if MyCustomFlexComp extends UIComponent
 // Otherwise, use corresponding AutomationImpl class. Eg if MyCustomFlexComp extends Panel, Use PanelAutomationImpl
{
private var myCustomFlexCompObjWalker:MyCustomFlexComp;

public function MyCustomFlexCompDelegate(objTabBar:MyCustomFlexComp):void
{
 super(objTabBar);
 myCustomFlexCompObjWalker = objTabBar;

 //optional
 myCustomFlexCompObjWalker.addEventListener(AutomationRecordEvent.RECORD,
                                                    labelRecordHandler);
 //optional
 myCustomFlexCompObjWalker.addEventListener(MouseEvent.CLICK,clickHandler);
}

public static function init(obj:DisplayObject):void
{
 Automation.registerDelegateClass(MyCustomFlexComp, MyCustomFlexCompDelegate);
}

override public function get numAutomationChildren():int
{
 return myCustomFlexCompObjWalker.numChildren;
}

override public function getAutomationChildAt(index:int):IAutomationObject
{
 var obj:IAutomationObject = (myCustomFlexCompObjWalker.getChildAt(index))
                                      as IAutomationObject;
 return obj;
}

//optional
override public function createAutomationIDPart(child:IAutomationObject):Object
{
 var help:IAutomationObjectHelper = Automation.automationObjectHelper;
 return help.helpCreateIDPart(myCustomFlexCompObjWalker, child);
}

//optional
override public function resolveAutomationIDPart(part:Object):Array{
 var help:IAutomationObjectHelper = Automation.automationObjectHelper;
 return help.helpResolveIDPart(uiAutomationObject, part);
}

public function clickHandler(event: MouseEvent): void //optional
{
 if(event.currentTarget==uiComponent)
 {
 event.stopImmediatePropagation();
 }
 else
 {
 var help:IAutomationManager = Automation.automationManager;
 help.recordAutomatableEvent(myCustomFlexCompObjWalker, event);
 }
}

override public function replayAutomatableEvent(event:Event):Boolean { //optional
 var help:IAutomationObjectHelper = Automation.automationObjectHelper;
 if (event is MouseEvent && event.type == MouseEvent.CLICK) {
 return help.replayMouseEvent(this, MouseEvent(event));
 } else {
 return super.replayAutomatableEvent(event);
 }
}

public function labelRecordHandler(event:AutomationRecordEvent):void { //optional
 // if the event is not from the owning component reject it.
 if (event.replayableEvent.target == uiComponent)
 event.stopImmediatePropagation();
 }}

}

TEAFlexCustom can also be updated, if you want to see your delegate name in QTP.
To update TEAFlexCustom.xml, refer TEAFlex.xml, and copy a full tag acting as a parent component to your custom component.

For Eg. If MyCustomFlexComp was extending UIComponent, copy that full <classinfo> tag from TEAFlex, paste in TEAFlexCustom and give the class name with full package  in the <implementation tag>instead of original flex implementation class. For clarity and assurance, change the name property in <ClassInfo> to MyCustomFlexCompDelegate.


<ClassInfo Name="<strong>MyCustomFlexCompDelegate</strong>" GenericTypeID="object" Extends="FlexDisplayObject" SupportsTabularData="false">

<IconInfo IconFile="TEAPluginQTP.dll" IconIndex="NaN"/>
 <Description>FlexObject</Description>
 <Implementation Class="<strong>test.components.MyCustomFlexComp</strong>"/>
 <TypeInfo>
 <Operation Name="Click" PropertyType="Method" ExposureLevel="CommonUsed">
 <Implementation Class="flash.events::MouseEvent" Type="click"/>
 <Argument Name="keyModifier" IsMandatory="false" DefaultValue="0">
 <Type VariantType="Enumeration" Codec="keyModifier" ListOfValuesName="FlexKeyModifierValues"/>
 <Description>A constant that indicates which key or key combination, if any, was pressed while this operation took place. One of: flexAlt, flexControl, flexControlAlt, flexControlShift, flexControlShiftAlt, flexShift, or flexShiftAlt. For example, if the Shift and Alt keys were pressed, then the value would be flexShiftAlt.</Description>
 </Argument>

There may be cases when more changes in delegate class needs to be required. and even then in certain components, not 100% of the custom components can’t be recognized. But with this info, a reasonable success can be achieved in Flex with QTP POC etc assignments.

Install FlexBuilder 3 Plugin with STS, Eclipse on windows

Once you have Installed Flex builder plug-in (FB3_WWEJ_Plugin) and an update FB3_Updater(if required) on top of it,  you will find the Flex sdk installed on your machine in the directory C:\Program Files\Adobe\Flex Builder 3 Plug-in.

There would also reside a folder called eclipse which contains features and plugin folders.

To install FB plugin in your eclipse , just copy the contents of C:\Program Files\Adobe\Flex Builder 3 Plug-in\eclipse\features to your eclipse. For eg (C:\eclipse-jee-indigo-SR2-win32\eclipse\features)  and the contents of C:\Program Files\Adobe\Flex Builder 3 Plug-in\eclipse\plugins to the respective plugins folder of your eclipse. Restart eclipse after that.

If you are using STS, do the following:

1) In the STS main directory, go to dropins (sts/dropins) and create a new directory there call FlexBuilder3 (sts/dropins/FlexBuilder3)

2) Now under the installed FB3 plugin (sts/Adobe Flex Builder 3 Plug-in) copy the entire “eclipse”  contents (C:\Program Files\Adobe\Flex Builder 3 Plug-in\eclipse) to this new directory just created in step 1 above ((sts/dropins/FlexBuilder3)

3) Start/Restart STS.

Setup Oracle11g connection and create a test user and table

Before you set-up Oracle11g on Windows ,  check for Microsoft Loopback Adapter as follows:

Go to command prompt, type System Drive:\> ipconfig /all , you should see the following entry along with other available connections:

Ethernet adapter Local Area Connection 2:
Connection-specific DNS Suffix  . :
Description . . . . . . . . . . . : Microsoft Loopback Adapter
Physical Address. . . . . . . . . : 02-00-4C-4F-4F-50
DHCP Enabled. . . . . . . . . . . : No
Autoconfiguration Enabled . . . . : Y   ………………….. and more

In case you find that loopback adapter is not installed, follow these steps:

Windows 7:

  1. Click the Start menu, typein “cmd”
  2. Right-click on “cmd” and select “Run as Administrator”
  3. Enter “hdwwiz.exe”
  4. In the “Welcome to the Add Hardware Wizard”, click Next.
  5. Select “Install the hardware that I manually select from a list (Advanced)” and click Next.
  6. Scroll down and select “Network adapters” and click Next.
  7. Select under Manufacturer “Microsoft” and then under Network Adapter “Microsoft Loopback Adapter” and click Next.

In Others, Go to Add Hardware wizard from Control Panel, Classic View, Add Hardware ->  Device Manager, right click on root node and select Add Legacy Hardware. then follow the above steps starting from 4.

Now you can proceed with Oracle setup.exe for Oracle11g installation.

1. Select “Advanced Installation” radio button.

2. Select Enterprise Edition.

3. Provide installation path(withou spaces) in Oracle base .

4. You can uncheck the checkbox if you wish not to receive security updates and click on Next button.

5. If you have unchecked the checkbox, you will be asked for confirmation. Click on Yes button in the confirmation dialog.

Note:  You’ll see the failure message if you’re installing Oracle 11g (11.1.0.7) on a Windows 7 operating system, which is actually version 6.1 according to their code control numbering. You simply check the Checking operating system requirements … and Checking service pack requirements … to override the prerequisite checks. Another error that you may encounter is related to networking. It is a warning and occurs when you’re operating system uses DHCP to get its IP address. You really should configure the operating system with a static IP address. Ignore the warnings and proceed.

6. Select Create a Database  and click Next.

7. Select General Purpose/Transaction Processing and click Next.

8. Specify a global database name of your choice and click Next ( Remember this. This is the service name/SID with which the listener will be created). Lets assume that you have enterted “MYSID” here.

9.  Select Enable Automatic Memory Management and click Next

10. Select Use Database Control for Database Management and click Next.

11. Select File System and click Next.

12. Select Do not enable Automated backups and click Next

13. Select either of the options, supply user name, password of your choice and click Next.

14. Click install and wait for installation to be completed.

Once you are through the set-up, let’s create a User

1. Open SQL PLus
user: system
password: password ( the password you gave while installing Oracle)

2. Use the following command to connect as a DBA
sql> CONNECT SYS AS SYSdba
password: password

3. Use the following command to create a user with a name testuser and password testuser( you can choose to keep a different password)
SQL> create user testuser identified by testuser;
User created.
4. Use the following command to grant all privileges to testuser
SQL> GRANT all privileges TO testuser;
Grant succeeded.

5. Then exit from sqlplus…
SQL> exit

Now, you have a Oracle DB Connection with the following URL:

jdbc:oracle:thin:@localhost:1521:MYSID
username: testuser
password: testuser

or the complete URL as:

jdbc:oracle:thin:testuser/testuser@localhost:1521:MYSID

Create a Connection and add a table under that connection

Go to SQL Developer ( already gets installed with Oracle), In windows 7, type SQL Developer in Run, you will find it.

In SQL Develpoer, click on Connections, Right click -> New Connection

Enter the connection name of your choice as  “mytestconn” (without quotes)
Username as testuser (created earlier)
Password as testuser (created earlier)
Keep hostname as localhost (default) and portnumber as 1521 (default)
Select SID radio button and provide the SID as MYSID (listener name which can also be found in tnsnames.ora)

Test the connection and connect (You should be successfully connected to mytestconn).

To Create a table, select the connection and go to SQL area,  and use the following command to create an Orders table:

create table orders (
order_id   number primary key,
order_dt   date,
order_type varchar2(50),
customer_name varchar2(50)
)

Run the Query and the table should be created.

Now, you are set to go further and start using your newly created DB :)

Why I Like Agile

Hello Reader,

I am writing this blog to express my gratitude to the method, which has defined ways to change the life of a developer from a resource to an individual.

Its been more than 2.5 years when I was introduced to the Framework. In the beginning when I heard about it, I took it as ‘just another way of project development’. But over the period of time I realized that “Being Agile” is more than that.

I was fortunate enough to work with the Organization who didn’t introduce Agile as just another process or because the Client wants to have it, but as their belief that Agile is a better way to do things including project work. Also, the people around and the client understood the Agile concept well and contributed significantly in adapting it in a good way.

Let me share the things I like being working AGILE way :

1. I became a team member, and I shared the credit for sprint success and failure EQUALLY every time, irrespective of my amount of contribution in the sprint.

2. I feel ‘BEING IMPORTANT‘, when I participate in Daily Stand-up sharing my work progress and picking up the task of my interest, and also when I participate in sprint planning.

3. I have a vision of ‘Demo Expectation‘ and I know where the task I am working on fits in.

4. I can pair program when a) I want to learn new things b)  when I get struck in something. It is PERFECTLY FINE to work on a single machine sitting and contributing to the task together.

5. I like the way my team fixed the problem as soon as they encounter one without having a discussion upon who caused the bug. They SHARE THE FIX RATHER THEN THE ISSUE.

6. I like the way Scrum Master COACHES the team and the new team members to bring them up to a pace.

7. I can plan my leaves well in advance taking into account the sprint goal in mind. And vice-verse, the velocity of the sprint will be calculated taking into account my planned leaves. 

8. I talk directly to the client and distributed team overseas without being dependent on anybody else.

Still I would say, there is more to AGILE.

However, when I say this, there are certain factors that contribute significantly in making the environment Agile friendly. By following the Agile Principles without understanding the real motive and without having the desired support and understanding of the concept by each one who is involved in the project or process, will not bring much difference to our lives. Hence, it is important that the value of key foundation elements of Agile like transparency, review and adaptation are understood before jumping in to the framework.

Wish you all a pleasant experience with Agile like me :)

Asynchronous Handling in JavaFx : Polling from Client

If you have chosen JavaFx as an interoperable language, might be over swings, then your most common use case will include following Sun’s guidelines that says “while creating the components or changing a component’s UI state you must do it inside the EDT (Event Dispatch Thread)”.

While your Swing application runs from the main thread, you will have to take care of threading as otherwise your application will behave unresponsive while doing long computations.

In JavaFx, every application always always runs inside the Event Dispatch Thread. This means that though you no longer have to worry about repaint issues when changing the state of your stages, but  you still need to take care of long computations as they will be run inside the EDT.

The javafx.asyncof JavaFx 1.2 package can be used when you need to perform any  background work like polling for some activity being done at the back end(say java) which you don’t want to run on the main JavaFX thread.

For example,  you are doing some file IOs, or maybe  some serious number update and if you do them on your main thread, the user would be blocked from performing anything on UI  as it will seem to be hanged.

Following is the way to implement this usecase in your JavaFx Application via two abstract classes namely JavaTaskBase and RunnableFuture

Read rest of the entry at : http://xebee.xebia.in/2011/03/22/polling-from-javafx/

Follow

Get every new post delivered to your Inbox.