Hibernate 4 Multi Tenancy Demo

Hibernate 4 : Multi Tenant Demo by Mahendra C Shinde

I. Prepare database
Using MySQL 5.5, created two schemas ‘db1’ and ‘db2’
Both contains identical table schema:

CREATE TABLE `books` (
bookId int(11) NOT NULL AUTO_INCREMENT,
title varchar(50) DEFAULT NULL,
PRIMARY KEY (`bookId`)
)

Add some data in both tables [make sure both tables contains different set of rows]

II. Prepare Hibernate Demo App
1. Create New Maven project without archetype selection
2. Add following dependencies to project:

        <dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>5.1.35</version>
  	</dependency>
  	<dependency>
  		<groupId>org.hibernate</groupId>
  		<artifactId>hibernate-core</artifactId>
  		<version>4.3.8.Final</version>
  	</dependency>

III. Prepare hibernate configuration:

	<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">mahendra</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.default_catalog">db1</property>
        <property name="hibernate.default_schema">db1</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    	<!-- multi-tenancy configuration -->    
        <property name="hibernate.multiTenancy">SCHEMA</property>
    	<property name="hibernate.multi_tenant_connection_provider">com.mahendra.MultiTenantConnectionProviderImpl</propertyx>
    	<property name="hibernate.temp.use_jdbc_metadata_defaults">false</property>
    	<mapping class="com.mahendra.Book"/>

And the HibernateUtil class to build SessionFactory:

package com.mahendra;

import org.hibernate.*;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

private static SessionFactory factory = build();

private static SessionFactory build() {
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder();
serviceRegistryBuilder.applySettings(configuration.getProperties());
ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
return configuration.buildSessionFactory(serviceRegistry);
}

public static SessionFactory factory() {
return factory;
}
}

IV, Prepare POJO Entity :

package com.mahendra;

import javax.persistence.*;

@Entity
@Table(name = "books")
public class Book {

@Id
@GeneratedValue
private Integer bookId;

@Column(name = "title", length = 50)
private String title;

@Override
public String toString() {
return "[" + getBookId() + "] " + getTitle();
}

public Integer getBookId() {
return bookId;
}

public void setBookId(Integer bookId) {
this.bookId = bookId;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}
}

V. Prepare ConnectionProvider for Multi-Tenancy

package com.mahendra;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.jboss.logging.Logger;

public class MultiTenantConnectionProviderImpl implements MultiTenantConnectionProvider, ServiceRegistryAwareService{

private DriverManagerConnectionProviderImpl provider =new DriverManagerConnectionProviderImpl();

private Logger log = Logger.getLogger(MultiTenantConnectionProviderImpl.class.getName());

public boolean isUnwrappableAs(Class arg0) {
return provider.isUnwrappableAs(arg0);
}

	public <T> T unwrap(Class<T> arg0) {
		return provider.unwrap(arg0);
	}


public Connection getAnyConnection() throws SQLException {
return provider.getConnection();
}

public Connection getConnection(String tenantId) throws SQLException {
Connection con = getAnyConnection();
try {
con.createStatement().execute("use "+tenantId);
log.info("Using "+tenantId+" as database schema");
}catch(SQLException ex) {
throw new HibernateException("Could not alter connection for specific schema");
}
return con;
}

public void releaseAnyConnection(Connection con) throws SQLException {
provider.closeConnection(con);

}

public void releaseConnection(String tenantId, Connection con)
throws SQLException {
try {
con.createStatement().execute("USE mysql");
System.out.println("Now, released "+tenantId);
}catch(SQLException ex) {
throw new HibernateException("Unable to reset");
}
provider.closeConnection(con);

}

public boolean supportsAggressiveRelease() {
return false;
}

public void injectServices(ServiceRegistryImplementor registry) {
Map settings = registry.getService(ConfigurationService.class).getSettings();
provider.configure(settings);
provider.injectServices(registry);

}
}

VI. The Main method to test

package com.mahendra;

import java.util.List;
import org.hibernate.*;

public class AppMain {

public static void main(String[] args) {
System.out.println("Books from db1");
loadBooksFrom("db1");
System.out.println("Books from db2");
loadBooksFrom("db2");
}

static void loadBooksFrom(String tenant) {
SessionFactory factory = HibernateUtil.factory();
Session session = factory.withOptions().tenantIdentifier(tenant).openSession();
List<Book> books = session.createQuery("from Book b").list();
for(Book b : books) {
System.out.println(b);
}
session.close();
}
}

Application will run, but need to close forcefully. This application creates a Service for SessionBuilder. Contact me if you have queries.

Advertisements

Spring And JSF with Hibernate Demo

Spring + Hibernate + JSF

Use following SQL Script to create table:


CREATE TABLE `products` (
`productId` int(8) NOT NULL,
`description` varchar(250) DEFAULT NULL,
`name` varchar(30) DEFAULT NULL,
`price` double DEFAULT NULL,
PRIMARY KEY (`productId`)
);

Sample Data :

| productId | description | name | price |
| 1 | Operating System for 128 Bit Systems | Mahendra OS 1.1 | 123000 |
| 2 | Office productivity Suite | Mahendra Office 2.0.1 | 63000 |
| 3 | IDE for Developing C,C++ and Java Applications | Mahendra IDE 2.3 | 543000 |

Frameworks Used:

Presentation Tier JSF 2.2
Business Tier Spring 3.1
Data Access Tier Hibernate 3

Dependencies [Actual JAR files]

  1. Hibernate 3

    • annotations-api.jar
    • cglib-2.2.jar
    • commons-collections.jar
    • commons-logging-1.1.1.jar
    • dom4j-1.6.1.jar
    • hibernate-jpa-2.0-api-1.0.0.Final.jar
    • hibernate3.jar
    • javassist-3.12.0.GA.jar
    • jta-1.1.jar
    • slf4j-api-1.6.1.jar
    • slf4j-simple-1.6.1.jar
  2. Spring 3

    • org.springframework.beans-3.1.0.M2.jar
    • org.springframework.context-3.1.0.M2.jar
    • org.springframework.context.support-3.1.0.M2.jar
    • org.springframework.core-3.1.0.M2.jar
    • org.springframework.expression-3.1.0.M2.jar
    • org.springframework.orm-3.1.0.M2.jar
    • org.springframework.transaction-3.1.0.M2.jar
    • org.springframework.web-3.1.0.M2.jar
    • org.springframework.jdbc-3.1.0.M2.jar
  3. Spring declarative Transactions

    • aopalliance-1.0.jar
    • asm-3.1.jar
    • org.springframework.aop-3.1.0.M2.jar
    • org.springframework.asm-3.1.0.M2.jar
  4. JSF 2.1

    • javax.faces-2.1.13.jar
    • jstl-1.2.jar
  5. JDBC Driver

    • mysql-connector-java-5.1.10-bin.jar

Create New Dynamic Web Project using eclipse with Apache Tomcat 6.0

Edit web.xml file to enable Spring

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Modify faces-config.xml to enable Spring EL inside JSF

<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>

Create hibernate.cfg.xml file inside ‘src’ folder

<!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">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">mahendra</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/world</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.current_session_context_class">thread</property>
<mapping class="com.mahendra.models.Product"/>
</session-factory>
</hibernate-configuration>

Create applicationContext.xml inside ‘WEB-INF’ folder

<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<tx:annotation-driven />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<bean id="ht" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

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

<bean id=”dao” class=”com.mahendra.springbeans.ProductDAO”>
<property name=”template” ref=”ht” />
</bean>
</beans>

create: Product.java


package com.mahendra.models;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.persistence.*;

@ManagedBean @RequestScoped
@Entity @Table(name=”products”)
public class Product {

@Id private Integer productId;
private String name;
private String description;
private double price;
//generate getters and setters…
}

create : ProductDAO.java


package com.mahendra.springbeans;
import java.util.List;
import java.util.logging.Logger;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.mahendra.models.Product;

@Service
public class ProductDAO {

private HibernateTemplate template;
private static Logger log = Logger.getLogger(ProductDAO.class.getName());
public HibernateTemplate getTemplate() {
return template;
}

public void setTemplate(HibernateTemplate template) {
this.template = template;
}

@Transactional
public void save(Product p){
log.info(“Preparing to save product “+p.getName());
template.save(p);

log.info(“Product “+p.getName()+ ” saved”);
}

@Transactional(readOnly=true)
public List findAll(){
List pl = null;
log.info(“Reading products from database”);
pl = template.loadAll(Product.class);
return pl;
}
}

Create ProductBean.java


package com.mahendra.jsfbeans;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import com.mahendra.models.Product;
import com.mahendra.springbeans.ProductDAO;
import java.util.logging.*;

@ManagedBean @ApplicationScoped
public class ProductBean {
private Product product;
private static Logger log = Logger.getLogger(ProductBean.class.getName());

private List productList;

@ManagedProperty(value=”#{dao}”)
private ProductDAO dao;

public Product getProduct() {
return product;
}

public void saveAction(){
log.info(“Saving product”);
dao.save(product);
listAction();
}

@PostConstruct
public void listAction(){
log.info(“Getting all products”);
setProductList(dao.findAll());
}

public void setProduct(Product product) {
this.product = product;
}

public List getProductList() {
return productList;
}

public void setProductList(List productList) {
this.productList = productList;
}

public ProductDAO getDao() {
return dao;
}

public void setDao(ProductDAO dao) {
this.dao = dao;
}
}

Create / Modify index.xhtml

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;
<html xmlns=”http://www.w3.org/1999/xhtml&#8221;
xmlns:ui=”http://java.sun.com/jsf/facelets&#8221;
xmlns:h=”http://java.sun.com/jsf/html&#8221;
xmlns:f=”http://java.sun.com/jsf/core”&gt;
<head>
<title>Mahendra’s Spring + Hibernate + JSF Demo</title>
</head>
<body>
<h:form>
<h2>Add new product</h2>
<h:panelGrid columns=”2″>
<h:outputLabel value=”Product ID” for=”pid”/>
<h:inputText id=”pid” value=”#{product.productId}”/>
<h:outputLabel value=”Product Name” for=”pn”/>
<h:inputText id=”pn” value=”#{product.name}”/>
<h:outputLabel value=”Description” for=”pd”/>
<h:inputTextarea cols=”25″ rows=”3″ id=”pd” value=”#{product.description}”/>
<h:outputLabel value=”Price” for=”pc”/>
<h:inputText id=”pc” value=”#{product.price}”/>
<h:commandButton value=”Save” action=”#{productBean.saveAction}” >
<f:setPropertyActionListener value=”#{product}” target=”#{productBean.product}”/>
</h:commandButton>
</h:panelGrid>
</h:form>
<h2>List of Existing Products</h2>
<h:form>
<h:dataTable var=”p” value=”#{productBean.productList}”>
<h:column>
<f:facet name=”header”>Product ID</f:facet>
<h:outputText value=”#{p.productId}”/>
</h:column>
<h:column>
<f:facet name=”header”>Name</f:facet>
<h:outputText value=”#{p.name}”/>
</h:column>
<h:column>
<f:facet name=”header”>Description</f:facet>
<h:outputText value=”#{p.description}”/>
</h:column>
<h:column>
<f:facet name=”header”>Price</f:facet>
<h:outputText value=”#{p.price}”/>
</h:column>
</h:dataTable>
</h:form>
</body>
</html>

JPA with JSF and Session Bean on Apache TomEE

Even though I am going to use Apache TomEE (Tomcat 7 +OpenEJB + OpenJPA), It will work on ANY JAVA EE 6 (Web Profile) Compatible Application server.

In this example I am trying to demonstrate how to use Apache TomEE for developing an Application made with JPA + EJB + JSF.

This demo application uses Apache derby (JavaDB) database which comes free of cost with JDK 7 downloads. You may use any other database with tiny changes to some configuration files.

Pre-requisites:

Preparations:

  1. Create Database [You may skip this if you are using any other database]
  2. Open Terminal / MS DOS prompt
  3. goto JAVA_HOME (on windows: C:\Program Files\Java\jdk1.7.x_xx)
  4. goto db\bin
  5. use command:    startNetworkServer
  6. open eclipse → create new workspace → using Data source Explorer connect to Derby connection properties:
    url: jdbc:derby://localhost:1527/sample;create=true
    username: app
    password: app
  7. Open SQL Scrapbook → execute following queries:
    create table Contact(
    contactId int primary key generated always as identity,
    first_name varchar(25),
    last_name varchar(35),
    phone_no varchar(15)
    );
    insert into contact(first_name,last_name,phone_no)
    values('Katrina','Kaif','1020131');
    insert into contact(first_name,last_name,phone_no)
    values('Kareena','Kapoor','10480131');
    insert into contact(first_name,last_name,phone_no)
    values('Prachi','desai','1045431');
  8. Add server to current workspace [You may skip this if you know how to do it]
    1. Open “Servers” view → Right click → New → Server → Apache: Apache Tomcat 7
    2. Click on “Browse” and provide path to your TomEE folder → Finish
    3. Double click on Apache Tomcat 7 inside “Servers” view
    4. Change “Server Locations” to “Use Tomcat Installation”

    [This must be done when BEFORE ANY PROJECT IS ADDED TO TOMCAT]

  9. Create New Dynamic Web Project
    1. New–> Dynamic Web Project → Name: TestApp2
    2. Click on “Modify” to change Configuration
    3. Select “JPA” and “JSF” project facets

    [ One Best thing about TomEE, it comes bundled with OpenJPA and JSF so forget about downloading and copying required JARs into your application’s WEB-INF/lib]

    • Create JNDI DataSource [MUST READ]
    • Stop Apache TomEE (If already started)
    • Open TomEE’s “conf” folder → Open “tomee.xml” in any text editor
    • add following resource definition:
      <Resource id="testDS" type="DataSource">
      JdbcDriver org.apache.derby.jdbc.ClientDriver
      JdbcUrl jdbc:derby://localhost:1527/sample
      UserName app
      Password app
      </Resource>
      

      [No, I have not made any mistake there!!]

    • Save & close this file
    • Add following “datasource” in persistence.xml testDS
  10. Create JPA entity for Table “Contact”
    package com.mahendra.models;
    import java.io.Serializable;
    import javax.persistence.*;
    /**
    * The persistent class for the CONTACT database table.
    *
    */
    @Entity
    public class Contact implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int contactid;
    @Column(name="FIRST_NAME")
    private String firstName;
    @Column(name="LAST_NAME")
    private String lastName;
    @Column(name="PHONE_NO")
    private String phoneNo;
    public Contact() {
    }public int getContactid() {
    return this.contactid;
    }public void setContactid(int contactid) {
    this.contactid = contactid;
    }public String getFirstName() {
    return this.firstName;
    }
    
    public void setFirstName(String firstName) {
    this.firstName = firstName;
    }
    
    public String getLastName() {
    return this.lastName;
    }
    
    public void setLastName(String lastName) {
    this.lastName = lastName;
    }
    
    public String getPhoneNo() {
    return this.phoneNo;
    }
    
    public void setPhoneNo(String phoneNo) {
    this.phoneNo = phoneNo;
    }
    
    }
  11. Your modified persistence.xml should look like this:
    <persistence version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="pu2">
    <jta-data-source>testDS</jta-data-source>
    <class>com.mahendra.models.Contact</class>
    </persistence-unit></persistence>
  12. Create new Java Class [It’s actually a session bean]
    package com.mahendra.services;
    import java.util.List;
    import javax.ejb.LocalBean;
    import javax.ejb.Stateless;
    import javax.persistence.*;
    import com.mahendra.models.Contact;/**
    * Stateless Session bean to save and/or list all contacts<br/>
    * We are using Java EE 6 Web Profile, so we don't need EJB Project
    * to create Stateless Session Beans!<br>
    * This is a CMT (Again thanks to Apache TomEE, It CAN make JTA data-sources
    * unlike plain Apache Tomcat which is just a Servlet Container)
    * @author Mahendra Shinde
    *
    */@Stateless @LocalBean
    public class ContactService {
    @PersistenceContext(unitName="pu2")
    private EntityManager em;
    public ContactService(){
    System.out.println("Instance created for Contact Service");
    }
    /**
    * method to create new record using provided arguments<br/>
    * TransactionAttribute for this method is REQUIRED (default)
    * @param firstName
    * @param lastName
    * @param phone
    */
    
    public void save(String firstName,String lastName,String phone){
    Contact cn = new Contact();
    cn.setFirstName(firstName);
    cn.setLastName(lastName);
    cn.setPhoneNo(phone);
    em.persist(cn);
    System.out.println("Record saved");
    }
    
    /**
    * method to load all contacts from database
    * @return List of all contacts
    */
    public List<Contact> loadAll(){
    List<Contact> list = null;
    Query q =em.createQuery("select c from Contact c");
    list = q.getResultList();
    return list;
    }
    
    }
  13. Create Managed Bean (Backing bean) for JSF pages:
    package com.mahendra.beans;
    import java.io.Serializable;
    import java.util.List;
    import javax.ejb.EJB;
    import javax.faces.bean.*;
    import com.mahendra.models.Contact;
    import com.mahendra.services.ContactService;
    /**
    * Backing Bean for JSF pages. <br/>
    * This bean has reference of <code>ContactService</code> using @EJB Annotation
    * @author Mahendra Shinde
    *
    */
    @ManagedBean
    @SessionScopedpublic class ContactBean implements Serializable {
    @EJB private ContactService service;
    private String firstName,lastName,phone;
    private List<Contact> contactList;
    public ContactBean() {
    }public String getFirstName() {
    return firstName;
    }
    
    public void setFirstName(String firstName) {
    this.firstName = firstName;
    }
    
    public String getLastName() {
    return lastName;
    }
    
    public void setLastName(String lastName) {
    this.lastName = lastName;
    }
    
    public String getPhone() {
    return phone;
    }
    
    public void setPhone(String phone) {
    this.phone = phone;
    }
    
    /**
    * Call save method on ContactService and update list
    * @return Outcome for JSF Navigation
    */
    
    public String addContact(){
    service.save(firstName,lastName,phone);
    contactList = service.loadAll();
    return "success";
    }
    
    public List<Contact> getContactList() {
    return contactList;
    }
    
    public void setContactList(List<Contact> contactList) {
    this.contactList = contactList;
    }
    
    }
  14. Add following navigation rule inside “faces-config.xml” file:
    <navigation-rule>
    <display-name>index.xhtml</display-name>
    <from-view-id>/index.xhtml</from-view-id>
    <navigation-case>
    <from-outcome>success</from-outcome>
    <to-view-id>/list.xhtml</to-view-id>
    <redirect />
    </navigation-case>
    </navigation-rule>
  15. Create “index.xhtml” inside “WebContents” folder:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html" ><h:head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <title>Home page</title>
    </h:head><h:body>
    <h:form>
    <h:outputText value="First name :" />
    <h:inputText value="#{contactBean.firstName}"/>
    <h:outputText value="Last name :" />
    <h:inputText value="#{contactBean.lastName}"/>
    <h:outputText value="Phone :" />
    <h:inputText value="#{contactBean.phone}"/>
    <h:commandButton value="submit" action="#{contactBean.addContact}"/>
    </h:form>
    </h:body>
    </html>
  16. create “list.xhtml” inside “WebContents” folder
    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"><h:head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <title>List of Contacts</title>
    </h:head><h:body>
    <h2>My Contacts</h2>
    <h:dataTable value="#{contactBean.contactList}" var="c">
    <h:column>
    <f:facet name="header">Contact #</f:facet>
    #{c.contactid}
    </h:column>
    <h:column>
    <f:facet name="header">First Name</f:facet>
    #{c.firstName}
    </h:column>
    <h:column>
    <f:facet name="header">Last Name</f:facet>
    #{c.lastName}
    </h:column>
    <h:column>
    <f:facet name="header">Phone #</f:facet>
    #{c.phoneNo}
    </h:column>
    </h:dataTable>
    </h:body>
    </html>
    
  17. Now, run your application on Apache TomEE
    [Make sure Apache Derby is Still running]
    test url : http://localhost:8080/TestApp2/faces/index.xhtml

Native Dependency Injection in Struts2

Struts2 Native Dependency Injection

Struts2 provides support for Dependency injection. You may use DI containers like “Spring” in your Struts2 application, or may use Native Dependency Injection available in Struts2 (XWork2) framework. It’s based on Google’s “guice” (both being made by same person).

In this sample application, I have made Two Action classes:

  1. AddProductAction           To Add new product
  2. ListProductAction            To List all products

Both actions are dependent on a “Business” class  : ProductManager. Instead of creating instance of ProductManager in each action class, I have created its instance through “bean” element in “struts.xml”.

<bean class="com.mahendra.ProductManager" name="man" />

The ObjectFactory available in Struts2 will create instance of ProductManager using default constructor and is made available to all other components using name : “man”.

Every Action class needs to have property of type “ProductManager” along with annotation:

@Inject("man")
private ProductManager manager;
// This method is used for Injecting Object
public void setManager(ProductManager manager) {
this.manager = manager;
}

Now, lets create an application.

Requirements:

  1. Java SDK 1.6 (or newer)
  2. Eclipse helios (or newer)
  3. Apache Tomcat 6.0 (or 7.0)
  4. Struts 2.1.x from apache

Steps to create application:

  1. Create new Dynamic Web Application.
  2. Copy all required JAR’s inside “web-inf/lib” folderJARS required:
    commons-fileupload
    commons-io
    commons-lang
    freemarker
    javassist
    ognl
    jstl (For JSTL Core Tags)
    struts2-core
    xwork-core
    
  3. Modify your “web.xml” to have Struts2 dispatcher filter.
    <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher
    </filter-class>
    </filter>
    <filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    
  4. Create new “struts.xml” in your source folder:
    <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
    <struts><bean class="com.mahendra.ProductManager"
    name="man" />
    
    <package name="p1" extends="struts-default"
    namespace="">
    <action name="add"
    class="com.mahendra.AddProductAction">
    <result type="redirectAction">list</result>
    </action> 
    
    <action name="list"
    class="com.mahendra.ListProductAction">
    <result>list.jsp</result>
    </action>
    </package>
    
    </struts>
    
  5. Create Model class : Product
    package com.mahendra;
    public class Product {
    
    private String name;
    private String description;
    private double price;
    
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public String getDescription() {
    return description;
    }
    public void setDescription(String description) {
    this.description = description;
    }
    public double getPrice() {
    return price;
    }
    public void setPrice(double price) {
    this.price = price;
    }
    
    public Product(String name, String description, double price) {
    super();
    this.name = name;
    this.description = description;
    this.price = price;
    }
    
    public Product() {
    super();
    }
    
    }
    
  6. Shared “Business” class :
    ProductManager

    package com.mahendra;
    
    import java.util.*;
    
    public class ProductManager {
    private List<Product> products;
    
    public ProductManager() {
    System.out.println("Creating new manager...");
    products = new LinkedList<Product>();
    System.out.println("Empty Product list generated");
    }
    
    public void add(Product p) {
    products.add(p);
    }
    
    public Product search(String name) {
    Product p = null;
    for (int i = 0; i < products.size(); i++) {
    if (products.get(i).getName().equals(name)) {
    p = products.get(i);
    break;
    }
    }return p;
    }
    
    public void delete(String name) {
    Product p = search(name);
    if (p != null) {
    products.remove(p);
    }
    }
    
    public List<Product> getProducts() {
    return products;
    }
    
    public void setProducts(List<Product> products) {
    this.products = products;
    }
    }
    
  7. Create First Action class to add new product: AddProductAction
    package com.mahendra;
    import com.opensymphony.xwork2.ActionSupport;
    import com.opensymphony.xwork2.inject.Inject;
    public class AddProductAction extendsActionSupport {
    @Inject("man")
    private ProductManager manager;
    private Product product;
    public String execute() {
    manager.add(product);
    return SUCCESS;
    }
    public ProductManager getManager() {
    return manager;
    }
    
    // This method is used for Injecting Object
    public void setManager(ProductManager manager) {
    this.manager = manager;
    }
    
    public Product getProduct() {
    return product;
    }
    
    public void setProduct(Product product) {
    this.product = product;
    }
    }
    
  8. Create another action class to List all products: ListProductAction
    import java.util.List;
    import com.opensymphony.xwork2.inject.Inject;
    
    public   class ListProductAction {
    
    @Inject("man")// requires setter 
    private ProductManager manager; 
    private List<Product> productList;
    
    public  String execute() {
    setProductList(manager.getProducts());
    return "success";
    }
    
    public  ProductManager getManager() {
     return  manager;
    }
    
    public void  setManager(ProductManager manager) {
    this.manager = manager;
    }
    
    public  List<Product> getProductList() {
     return  productList;
    }
    
    public void setProductList(List<Product> productList) {
     this.productList = productList;
    }
    }
    
  9. Create new JSP page “index.jsp” and add following line to load “list” action.
    <% response.sendRedirect("list.action"); %>
    
  10. Create new JSP page “list.jsp” and add following lines to render form and list.
    <%@ taglib uri= "/struts-tags"  prefix= "s"%>
    <html>
    <head>
    <meta http-equiv= "Content-Type"  content= "text/html;charset=ISO-8859-1" >
    <title>Struts2 Dependency Demo</title>
    </head>
    <body>
    
    <s:form action="add"  method="post" >
    <s:textfield name= "product.name" label= "Name of product" />
    <s:textfield name= "product.description" label= "Description"/>
    <s:textfield name= "product.price" label= "Product Price"  />
    <s:submit value= "Save"  />
    </s:form>
    
    <h2>Available Products</h2>
    <table>
    <tr>
    <td>Product Name</td>
    <td>Description</td>
    <td>Price</td>
    </tr>
    <s:iterator value= "productList"  var= "p" >
    <tr>
    <td>${p.name }</td>
    <td>${p.description }</td>
    <td>${p.price }</td>
    </tr>
    </s:iterator>
    </table>
    </body>
    </html>
    

Creating Seam2 ejb application on eclipse using Seam Tools and JBoss AS

Creating new Seam 2 EJB application on JBoss AS 5.1 using eclipse indigo.

My Configuration:
eclipse (indigo) with JBoss Tools installed at d:\seam-dev\eclipse
<JBOSS-AS>         JBoss AS 5.1.0 installed at D:\seam-dev\jboss-5.1.0.GA
<SEAM-HOME>      D:\jboss-seam-2.2.2.Final

Preparations:
create new workspace for eclipse
add Jboss AS 5.1 from above location to workspace (use “default” server profile)
copy hsqldb.jar from <SEAM-HOME>\lib to <JBOSS-AS>\lib folder.

Steps to create EMPTY EJB application :
1    Create new “Seam Web Project” with name Test-ent1 –> use JBoss AS 5.1 as server with default settings –>next


2    Use libaries provided by Runtime for JSF –>next


3    Application type: EAR with two modules : test-ent1-ejb and test-ent1-ear


4    Database connection : create new HSQL DB connection to database (empty database)
5    finish to create application.


6    Click on run to Run created application on JBoss AS 5.1 (data source first!  + test-ent1.ear)


NOTE: “war” module is part of “ear” so no need to run “Test-ent1” (war module) directly on server!
7    Incase if you got 404 error, just wait for server to finish loading (see server log in output panel) and then refresh page.

Steps to add “Entities”:
1    New –> New Seam
Entity : entity name: person


2    Open “Person.java” , add following two fields

 @Length(max=300)
 private String address;
 @Length(max=12,min=8)
 private String contact;

3    Generate getters and setters for them.
4    Open person.xhtml (from test-ent1 project), add follwoing lines just after “</s:decorate>”

 <s:decorate id="addressField" template="layout/edit.xhtml">
 <ui:define name="label">Address</ui:define>
 <h:inputText id="address" required="true"
 value="#{personHome.instance.address}"/>
 </s:decorate>
 <s:decorate id="contactField" template="layout/edit.xhtml">
 <ui:define name="label">Contact Number</ui:define>
 <h:inputText id="contact" required="true"
 value="#{personHome.instance.contact}"/>
 </s:decorate>

5    Open personList.xhtml page, change columns (inside <h:dataTable> )to following:

 <h:column>
 <f:facet name="header">Id</f:facet>
 #{person.id}
 </h:column>
 <h:column>
 <f:facet name="header">Name</f:facet>
 #{person.name}
 </h:column>
 <h:column>
 <f:facet name="header">Address</f:facet>
 #{person.address}
 </h:column>
 <h:column>
 <f:facet name="header">Phone number</f:facet>
 <s:link id="person"
 value="#{person.contact}"
 propagation="none"
 view="/person.xhtml">
 <f:param name="personId"
 value="#{person.id}"/>
 </s:link>
 </h:column>

6    Remove application from Server.


7    add following line inside “layout\menu.xhtml” to create menu item (only if not generated by eclipse)

 <s:link id="menuPersonListId" view="/personList.xhtml" value="Person" propagation="none"/>

8    Run application (causing un-deploy and then deploy)

Convert Seam2 example to eclipse project

Convert Seam example applications to eclipse Project

Project folder structure in seam 2. x examples is different than folder structure used by seam tools project.(Project created in eclipse using JBoss Tools).

Seam (JBoss) Tools  project:

  1. src/
    1. hot/
      1. <ALL-Action-classes>
      2. <other-classes-for-HOT-deployment>
      3. seam.properties <empty file>
    2. main/
      1. <ALL-entity/model-classes>
      2. components.propeties
      3. import.sql (Database DDL and DML statements)
      4. messages_en.properties
      5. security.drl
      6. seam.properties <empty file>
      7. META-INF/
        • persistence.xml
  2. WebContent/
    1. css/
    2. img/
    3. META-INF/
      1. context.xml
    4. <All-xhtml-pages>
    5. <All-xhtml.xml-pages>
    6. WEB-INF/
      1. classes/
      2. web.xml
      3. component.xml
      4. faces-config.xml
      5. jboss-web.xml (only for JBoss AS)
      6. pages.xml
  3. hibernate-console.properties
  4. <project_name>.launch

Convert “jboss-seam-jpa” example Application to eclipse (Seam) project.

1         Create new “Seam Web Project” à enter name of project “jboss-seam-jpa”

2         accept all details in above screen and press “Next” àNextàNext

3         Disable Library configuration for JSF capabilities (You need to copy all JAR’s manually to Tomcat’s LIB folder) àNext

4         Select (Or add new) JBoss Seam Runtime

  1. Deploy As :                          WAR
  2. Libraries:                             Copy library from Seam Runtime
  3. Database Type:                 Select HSQL
  4. Connection Profile:         create new Connection profile for HSQL DB
  5. DB Tables already exists in Database: FALSE
  6. Recreate Database tables and data on deploy : TRUE
  7. Package name(session):             org.jboss.seam.example.jpa
  8. Package name(Entity):                 org.jboss.seam.example.jpa
  9. Create Test Project:                      NO

5         Now click finish to generate Project

6         Now create new Package “org.jboss.seam.example.jpa” under source folder “src/main”

7         Delete auto-created “Authenticator.java” from src/hot

8         Open <SEAM-HOME> /LIB folder, copy following files:

Hibernate:

  1. hibernate-core.jar
  2. hibernate-annotations.jar
  3. hibernate-commons-annotations.jar
  4. hibernate-entitymanager.jar
  5. hibernate-search.jar
  6. lucene.jar (ONLY FOR SEAM VER = 2.2.2.FINAL)
  7. hibernate-validator.jar

JSF 1.2:

  1. jsf-api.jar
  2. jsf-impl.jar
  3. jsf-facelets.jar

JPA:

  1. jta.jar
  2. persistence-api.jar
  3. ejb3-persistence.jar (used by hibernate+JPA)

Logging for Hibernate and Seam:

  1. log4j.jar
  2. slf4j-api.jar
  3. slf4j-log4j12.jar
  4. log4j.properties (for debug messages)

Database Driver

1    hsqldb.jar

Drools:

  • drools-api.jar
  • drools-compiler.jar
  • drools-core.jar
  • drools-decisiontables.jar
  • drools-templates.jar

9         paste them all inside <TOMCAT-HOME>/LIB

10     Open <SEAM-HOME>/examples/jpa folder

11     open “src/org/jboss/seam/example/jpa” folder

12     Copy all java classes which ends with “Action”

13     inside eclipse goto src/hot/org/jboss/seam/example/jpa folder à delete existsing classes

14     inside eclipse, goto src/hot/org/jboss/seam/example/jpa folder à paste

15     copy remaining files from “src/org/jboss/seam/example/jpa” folder to src/main/org/jboss/seam/example/jpa folder

16     inside eclipse, delete all .xhtml and .xml files from WebContent folder, delete “css” , “img” & “layout” folders

17     Open “VIEW” folder of examples /jpa àcopy all files

18     inside eclipse, paste them all in “WebContent” folder (Overwrite duplicates)

19     Open “Resource-tomcat” folder from your examples/jpa

20     copy import.sql file

21     inside eclipseà paste it in src/main

22     Copy “persistence.xml” from resource-tomcat/META-INF to eclipse project’s src/main/META-INF

23     Copy “context.xml” from resource-tomcat/META-INF to eclipse project’s WebContent/META-INF

24     copy “WEB-INF” folder from resources-tomcat to eclipse project’s WebContent folder (Overwrite existsing WEB-INF)

Seam 2.2.2.Final with Apache Tomcat 7.0

From last three days, I was messing up with Seam 2.2, trying to get it work with Tomcat 7.

Seam can work with JBoss AS, GlassFish & other AS. but Tomcat being just a Servlet Container has many drawbacks.

My Setup:

  • JDK 1.7.0
  • Apache Tomcat 7.0
  • eclipse indigo (JBossTools  for indigo installed)
  • Seam 2.2.2.Final
  • JPA with Transaction type: RESOURCE_LOCAL (an alternative to default JTA)
  • Database : MySql 5.1 with MySql J/Connection 5.1

From Seam 2.2.2Final distribution, locate LIB folder, copy following JARs to tomcat 7/LIB folder:

Hibernate dependencies:

  1. annotations-api.jar
  2. cglib-nodep.jar
  3. commons-collections.jar
  4. commons-logging.jar
  5. dom4j.jar
  6. javassist.jar

Hibernate:

  1. hibernate-core.jar
  2. hibernate-annotations.jar
  3. hibernate-commons-annotations.jar
  4. hibernate-entitymanager.jar
  5. hibernate-search.jar
  6. lucene.jar
  7. hibernate-validator.jar

JSF 1.2:

  1. jsf-api.jar
  2. jsf-impl.jar
  3. jsf-facelets.jar

JPA:

  1. jta.jar
  2. persistence-api.jar
  3. ejb3-persistence.jar (used by hibernate+JPA)

Logging for Hibernate and Seam:

  1. log4j.jar
  2. slf4j-api.jar
  3. slf4j-log4j12.jar
  4. log4j.properties (for debug messages)

Drools:

  • drools-api.jar
  • drools-compiler.jar
  • drools-core.jar
  • drools-decisiontables.jar
  • drools-templates.jar

Now,after adding all these JAR’s your tomcat, your tomcat is ready to host seam 2.2 application.

  1. Create new Seam Web Project in eclipse
    Step 1
  2. Use Apache Tomcat 7.0 as Application Server (add if not done already)
  3. use selected configuration (which includes Seam 2.2)
  4. JSF Configuration: Disable Library configuration (We have added all JSF 1.2 Jars to our Tomcat)
  5. Use Seam Runtime : <<select folder where  you have extracted Seam 2.2.2>>
  6. Use Database connection New MSQL (Click on “New” button to create new connection, make sure that you have already created one EMPTY database in MySQL with name TestDB2)
  7. Click Finish to end project creation.
  8. Now, open “Package Explorer” 
  9. Inside package explorer … now you will get “WebContent” Folder which contains another one “META-INF” folder. I will now create context.xml inside this folder. This context will be deployed at the time of application deployment, which will result in deploying a (local) javax.sql.DataSource to Tomcat for current web application.
    <?xml version="1.0" encoding="UTF-8"?>
    <Context path="/TestApp15" docBase="TestApp15" crossContext="true">
        <Resource name="MyData" auth="Container" 
            type="javax.sql.DataSource"
            driverClassName="com.mysql.jdbc.Driver"
            username="root" password="mahendra" 
            url="jdbc:mysql://localhost:3306/TestDB2"/>
    </Context>
  10. Now, there is another META-INF inside src/main with one “persistence.xml”. make few changes in it:
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Persistence deployment descriptor for dev profile -->
    <persistence xmlns="http://java.sun.com/xml/ns/persistence" 
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" 
                 version="1.0">
    
       <persistence-unit name="TestApp15PU" transaction-type="RESOURCE_LOCAL">
          <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <non-jta-data-source>java:comp/env/MyData</non-jta-data-source>
          <properties>
             <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
             <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
             <property name="hibernate.show_sql" value="true"/>
             <property name="hibernate.format_sql" value="true"/>
             <property name="hibernate.default_catalog" value="TestDB2"/>
    
          </properties>
       </persistence-unit>
    </persistence>
  11. We are using NON JTA data source instead of default JTA, we are not using any Caching provider from Hibernate so remove Caching provider if any.
  12. From WebContents/WEB-INF folder, open “components.xml”, make following changes:
    <?xml version="1.0" encoding="UTF-8"?>
    <components xmlns="http://jboss.com/products/seam/components"
                xmlns:core="http://jboss.com/products/seam/core"
                xmlns:persistence="http://jboss.com/products/seam/persistence"
         xmlns:tx="http://jboss.com/products/seam/transaction"
                xmlns:drools="http://jboss.com/products/seam/drools"
                xmlns:bpm="http://jboss.com/products/seam/bpm"
                xmlns:security="http://jboss.com/products/seam/security"
                xmlns:mail="http://jboss.com/products/seam/mail"
                xmlns:web="http://jboss.com/products/seam/web"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation=
                    "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.2.xsd
                     http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.2.xsd
         http://jboss.com/products/seam/transaction http://jboss.com/products/seam/transaction-2.1.xsd 
                     http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.2.xsd
                     http://jboss.com/products/seam/bpm http://jboss.com/products/seam/bpm-2.2.xsd
                     http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.2.xsd
                     http://jboss.com/products/seam/mail http://jboss.com/products/seam/mail-2.2.xsd
                     http://jboss.com/products/seam/web http://jboss.com/products/seam/web-2.2.xsd
                     http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.2.xsd">
            <core:init />
       <core:manager concurrent-request-timeout="500"
                     conversation-timeout="120000"
                     conversation-id-parameter="cid"
                     parent-conversation-id-parameter="pid"/>
       <!-- Make sure this URL pattern is the same as that used by the Faces Servlet -->
       <web:hot-deploy-filter url-pattern="*.seam"/>
       <!-- If you are still using JBoss 4, uncomment this to have your PU started -->
    <!--   <persistence:entity-manager-factory name="entityManagerFactory"-->
    <!--                      persistence-unit-name="TestApp15"/>-->
       <!-- If you are still using JBoss 4, uncomment this to have the entityManagerFactory ysed -->
    <!--   <persistence:managed-persistence-context name="entityManager" auto-create="true"-->
    <!--                          entity-manager-factory="#{entityManagerFactory}"/>-->
            <tx:entity-transaction entity-manager="#{entityManager}" auto-create="true"/>
      <persistence:managed-persistence-context 
                   name="entityManager" 
                   auto-create="true"
                   entity-manager-factory="#{entityManagerFactory}"/>
      <persistence:entity-manager-factory 
                   name="entityManagerFactory" 
                   auto-create="true" 
                   persistence-unit-name="TestApp15PU"/>
       <drools:rule-base name="securityRules">
          <drools:rule-files><value>/security.drl</value></drools:rule-files>
       </drools:rule-base>
       <security:rule-based-permission-resolver security-rules="#{securityRules}"/>
       <security:identity authenticate-method="#{authenticator.authenticate}" remember-me="true"/>
       <event type="org.jboss.seam.security.notLoggedIn">
          <action execute="#{redirect.captureCurrentView}"/>
       </event>
       <event type="org.jboss.seam.security.loginSuccessful">
          <action execute="#{redirect.returnToCapturedView}"/>
       </event>
       <mail:mail-session host="localhost" port="25"/>
       <!-- For use with jBPM pageflow or process management -->
       <!--
       <bpm:jbpm>
          <bpm:process-definitions></bpm:process-definitions>
          <bpm:pageflow-definitions></bpm:pageflow-definitions>
       </bpm:jbpm>
       -->
    </components>
  13. Run application in Tomcat.

NOTE: You may download Video screen cast for the above demo at my box account

How to create WebService in JBoss AS7 using eclipse.

JBoss Application Server 7.1 comes bundled with JBossWS component. This component is based on Apache CXF. So those people who know Apache CXF, you will love JBoss AS.

First of all, you need to have few basic requirements:

JDK 1.7 (JDK 1.6 is sufficient, but using newest one is recommended)

eclipse indigo (Java EE developer) from eclipse.org

JBoss AS7

JBoss Tools:

You cannot immediately start developing applications for JBoss AS7. You need to get Plugins for your eclipse.

Open eclipse –> Help –> Install new software

add following URL :  http://download.jboss.org/jbosstools/updates/development/indigo

now expand “JBoss Web and JavaEE development”

select following components:

  • JBossAS Tools
  • JBoss WebServices Tools
  • Hibernate Tools
  • JBoss JAX-RS Tools

Now, install all these components.

Once installation in complete, you need to restart eclipse.

Now, add JBoss AS7 as WebServer to your eclipse workspace.

Now, click finish to add JBossAS7 to your eclipse workspace.

Create new Dynamic Web Project:

now, click on “Modify” button to change configuration, select “JBoss Web Services Core”

Click OK –> next –> Generate Web.xml = true –> Next

Image

Select “Server Supplied JBossWS runtime”

click Finish.

Create new class: Calculator

Image

NOTE: This step can be safely SKIPPED!

Create new WebService:

click on WebService Runtime: Apache Axix (in configuration section above) select JBossWS

Click OK

Image

Click Next

Select both option –> Next

Click on “Start Server” –> Wait for Server startup –> Next –> Finish

Now, right click on your project name (My project name is “MyServiceApp1” –>Run as –> Run on Server

change URL in web-browser to include your service name eg. http://localhost:8080/MyServiceApp1/Calculator?wsdl

(Please change port no and application name if they are different)

I you get to see wsdl for newly created web services then you are done!

You can now test this web service using eclipse:

goto Run menu –> Lauch web services explorer

Image

click on “WSDL page” button in top-right  corner

Image

Once you click on “Go” button, you will be presented a page where you can test this Service

Image

now, click on link to method “sum”

enter two value and click go..

Image

It’s done….