Friday, 14 October 2011

Dependency Injection or Context Lookup a stateful session bean

First create a stateful session bean

@Stateful(name="stateful")
@Local(Session.class)
public class StatefulSessionBean 
    implements Session {

    private int result;
    
    @Override
    public void add() {
        result++;
    }

    @Override
    public int get() {
        return result;
    }
}

Then create a servlet to Dependency Inject the stateful session bean

public class StatefulDependencyInjectionServlet 
    extends HttpServlet {
   
    @EJB(beanName="stateful")
    private Session stateful;
    
    @Override
    protected void doGet(HttpServletRequest req, 
        HttpServletResponse resp)
            throws ServletException, IOException {
        HttpSession session = req.getSession(true);
        Session bean = (Session)session.getAttribute("stateful");
        if (bean == null){
            bean = this.stateful;
        }
        bean.add();
        System.out.println("Stateful: " + bean.get());
        session.setAttribute("stateful", bean);
        
    }
} 

Test the servlet several times and check the result

[24/08/11 14:30:00:234 EST] 00000016 SystemOut O Stateful: 1
[24/08/11 14:30:03:234 EST] 00000016 SystemOut O Stateful: 2
[24/08/11 14:30:06:203 EST] 00000016 SystemOut O Stateful: 3

It seems working fine. But if we close the browser, open it again and test the servlet several times, we will see:

[24/08/11 14:33:15:812 EST] 00000016 SystemOut O Stateful: 4
[24/08/11 14:33:16:718 EST] 00000016 SystemOut O Stateful: 5
[24/08/11 14:33:17:328 EST] 00000016 SystemOut O Stateful: 6

This behaviour is incorrect as when the browser is closed and reopened, it represents a new client, who should get a new instance of stateful session bean.

Now create another servlet to access the stateful session bean through Context Lookup.

@EJB(name="ejb/stateful", 
     beanInterface=Session.class, 
     beanName="stateful")
public class StatefulContextLookupServlet 
extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, 
        HttpServletResponse resp)
            throws ServletException, IOException {
        HttpSession session = req.getSession(true);
        Session stateful = (Session)session.getAttribute("stateful");
        if (stateful == null){
            try{
                Context ctx = new InitialContext();
                stateful = (Session)ctx.lookup
                    ("java:comp/env/ejb/stateful");
            }catch (Exception e) {
                throw new EJBException(e);
            }    
        }
        stateful.add();
        System.out.println("Stateful: "+stateful.get());
        session.setAttribute("stateful", stateful);
        
    }
}

Test the servlet several times and check the result

[24/08/11 14:38:42:250 EST] 00000016 SystemOut O Stateful: 1
[24/08/11 14:38:45:453 EST] 00000016 SystemOut O Stateful: 2
[24/08/11 14:38:46:000 EST] 00000016 SystemOut O Stateful: 3

Close the browser, open it again and test the servlet several times

[24/08/11 14:39:38:734 EST] 00000016 SystemOut O Stateful: 1
[24/08/11 14:39:39:796 EST] 00000016 SystemOut O Stateful: 2
[24/08/11 14:39:40:546 EST] 00000016 SystemOut O Stateful: 3

Now the behaviour is correct.

Configure Derby JDBC resource in WebSphere 7

Assume the URL for Derby connection is
jdbc:derby://localhost:1527/C:\Data\derbydb\mydb

Go to Websphere Application Server 7 Admin Console

Resources->JDBC->JDBC Providers



Click on 'New' button


Click on 'Next' button


Click on 'Finish' button



Click on 'Save'



Click on ‘Data sources’


Click on ‘New’


Click on ‘Next’


Click on ‘Next’


Click on ‘Next’


Click on ‘Next’


Click on ‘Finish’


Click on ‘Save’


Click on ‘Test connection’

This message means the configuration is successful.

Sunday, 9 October 2011

A simple JSF 2.0 Web Application in MyEclipse 8.5

The project structure will look like:



Create a new Web Project in My Eclipse.


Add pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"      
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0     
    http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>jsf2</groupId>
    <artifactId>jsf2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name />
    <description />
    <dependencies>
        <dependency>
            <groupId>org.apache.openejb</groupId>
            <artifactId>javaee-api</artifactId>
            <version>5.0-1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.1.0-b03</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.1.0-b03</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Run maven, mvn eclipse:eclipse clean install


Refresh the project.

Create a java class: HelloBean.java

package bean;

import java.io.Serializable;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean(name="hello")
@SessionScoped
public class HelloBean implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Create hello.xhtml and welcome.xhtml under src/main/webapp

hello.xhtml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.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>
        <title>JSF 2.0 Hello World</title>
    </h:head>
    <h:body>
        <h3>JSF 2.0 Hello World Example - hello.xhtml</h3>
        <h:form>
            <h:inputText value="#{hello.name}"></h:inputText>
            <h:commandButton value="Welcome Me" action="welcome" />
        </h:form>
    </h:body>
</html>

welcome.xhtml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.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>
        <title>JSF 2.0 Hello World</title>
    </h:head>
    <h:body bgcolor="white">
        <h3>JSF 2.0 Hello World Example - welcome.xhtml</h3>
        <h4>Welcome #{hello.name}</h4>
    </h:body>
</html>

Deploy the application into Glassfish 3.1

Test http://localhost:8080/jsf2/hello.faces


Result

Monday, 3 October 2011

Derby installation

Download the latest derby release from http://db.apache.org/derby/

Unzip the downloaded zip file to c:\Java

In the command line, go to the lib folder under extracted derby folder. e.g.

cd C:\Java\db-derby-10.9.1.0-bin\lib

Start the derby server by

java -jar derbynet.jar start










Open another command line window, go to the folder in which you will create the derby database

e.g. cd C:\derbydb

Connect the derby server with the ij derby tool

java -jar C:\Java\db-derby-10.9.1.0-bin\lib\derbyrun.jar ij




Create the database named ‘mydb’

CONNECT 'jdbc:derby://localhost:1527/c:\derbydb\mydb;create=true';




create table STUDENT (stuid int, name varchar(10));
insert into STUDENT values (1, 'Wang');






exit;





Test the connection in Squirrel




Note: User Name and Password can be anything but empty.

Wednesday, 14 September 2011

Configure MySQL datasource in Glassfish 3.1

Part 1 of this article shows how to configure a MySQL datasource in Glassfish 3.1.

Part 2 of this article shows how to test the connection with a standalone Java client program.


Part 1

Assume Glassfish's installation folder is D:\glassfish3\glassfish

Copy mysql-connector-java-xxx-bin.jar to D:\glassfish3\glassfish\lib or D:\glassfish3\glassfish\domains\domain1\lib\ext

Start MySQL server, assume the following settings

URL: jdbc:mysql://localhost:3306/mydb
username: root
password: root

Start Glassfish, go to Admin Console, http://localhost:4848

Resources -> JDBC -> JDBC Connection Pools


Click on 'New'


Click on 'Next'


Scroll down, specify the following properties, and leave others as they are.


User  root
Password  root
Url  jdbc:mysql://localhost:3306/mydb
URL  jdbc:mysql://localhost:3306/mydb

Click on 'Save'

Go to Resources -> JDBC -> JDBC Resources


Click on 'New'


Click on 'OK'


Click on 'Ping' to test.

Part 2

Create a java project in Eclipse (must use JDK 1.6)

import java.sql.Connection;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) 
      throws Exception{
        Context ctx = new InitialContext();
        DataSource ds 
          = (DataSource) ctx.lookup("jdbc/mysql");
        Connection con = ds.getConnection();
        con.close();
    }
}

Add the following two jar files to class path


Note: You can't directly copy gf-client.jar into project's folder. You have to point to the jar file under glassfish\lib

After starting MySQL server and Glassfish Server, we can test the program.

REQUIRED VS REQUIRES_NEW transaction attribute type

This article uses code examples to illustrate the difference between REQUIRED and REQUIRES_NEW transaction attribute type.

Create two entity beans.

@Entity
@Table(name="T_COMPANY")
public class Company{
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "NAME")
    private String name;
    
    public Company() {
        super();
    }
    
    public Company(String name) {
        super();
        this.name = name;
    }
}


@Entity
@Table(name="T_PERSON")
public class Person{
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "NAME")
    private String name;
    
    public Person() {
        super();
    }
    
    public Person(String name) {
        super();
        this.name = name;
    }
}

Create a stateless session bean (companyBean) with a method having REQUIRES_NEW transaction attribute type.

@Stateless(name="companyBean")
@Local(CompanyManager.class)
public class CompanyManagerBean 
    implements CompanyManager {

    @PersistenceContext(unitName="unit")
    private EntityManager em;
    
    @Override
    @TransactionAttribute
    (TransactionAttributeType.REQUIRES_NEW)
    public void save(Company company) {
        em.persist(company);
    }
}

Create another stateless session bean (personBean), and inject the companyBean into the personBean.

@Stateless(name="personBean")
@Local(PersonManager.class)
public class PersonManagerBean 
    implements PersonManager {

    @PersistenceContext(unitName="unit")
    private EntityManager em;
    
    @EJB(beanName="companyBean")
    private CompanyManager companyManager;
    
    @Override
    @TransactionAttribute
    (TransactionAttributeType.REQUIRED)
    public void save(Person person) {
        companyManager.save(new Company("Oracle"));
        em.persist(person);
    }
} 

Write a servlet to test

public class PersonServlet extends HttpServlet {

    @EJB(beanName="personBean")
    private PersonManager personManager = null;
    
    @Override
    protected void doGet(HttpServletRequest req, 
            HttpServletResponse resp)
            throws ServletException, IOException {
        personManager.save(new Person("Mingtao001"));
    }
}

Result:

Table T_COMPANY



Table T_PERSON



Now throw an exception in personBean

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void save(Person person) {
    companyManager.save(new Company("Oracle"));
    em.persist(person);
    throw new RuntimeException("error!");
}

Clean the table and retest the servlet

Result:

Table T_COMPANY



Table T_PERSON


The SQL that saves the person has been rolled back while the SQL that saves the company was not affected.

Now change the transaction attribute type from REQUIRES_NEW to REQUIRED in companyBean.

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void save(Company company) {
    em.persist(company);
}

Clean the table and retest the servlet

Result:

Table T_COMPANY



Table T_PERSON



Both SQLs have been rolled back as they are in the same transaction.

Monday, 12 September 2011

Transaction VS Extended Persistence Context Type

This article uses code examples to illustrate the difference between TRANSACTION and EXTENDED persistence context type.

Firstly create an entity class

@Entity
@Table(name="T_PERSON")
public class Person{
    
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    
    @Column(name = "NAME")
    private String name;
    
    public Person() {
        super();
    }
    
    public Person(String name) {
        super();
        this.name = name;
    }
}

Create a TRANSACTION persistence context type in a stateful session bean.

@Stateful(name="transactionPersistenceContextBean")
@Local(TransactionService.class)
public class TransactionPersistenceContextBean 
    implements TransactionService {

    @PersistenceContext(unitName="unit", 
            type=PersistenceContextType.TRANSACTION)
    private EntityManager em;
    
    private Person person;
    
    @Override
    public void save(String name) {
        person = new Person(name);
        em.persist(person);
    }

    @Override
    public void update(String name) {
        person.setName(name);
        em.flush();
    }
}

Create an EXTENDED persistence context type in a stateful session bean.

@Stateful(name="extendedPersistenceContextBean")
@Local(TransactionService.class)
public class ExtendedPersistenceContextBean 
    implements TransactionService {

    @PersistenceContext(unitName="unit", 
            type=PersistenceContextType.EXTENDED)
    private EntityManager em;
    
    private Person person;
    
    @Override
    public void save(String name) {
        person = new Person(name);
        em.persist(person);
    }

    @Override
    public void update(String name) {
        person.setName(name);
        em.flush();
    }
}

Create a servlet to test

public class PersistenceContextServlet
   extends HttpServlet {
    
    @EJB(beanName="transactionPersistenceContextBean")
    //@EJB(beanName="extendedPersistenceContextBean")
    private TransactionService service;
    
    @Override
    protected void doGet(HttpServletRequest req, 
            HttpServletResponse resp)
            throws ServletException, IOException {
        service.save("abcde");
        service.update("defgh");
    }
}

The result for TRANSACTION Persistence Context


The result for EXTENDED Persistence Context


For TRANSACTION Persistence Context type, when the save method is complete, person instance is detached. So when the update method is invoked, person instance is not associated with the database session. So any changes made to person instance cannot be synchronized to the database.

For EXTENDED Persistence Context type, when the save method is complete, person instance is still managed by the database session. So when the update method is invoked, any changes made to person instance will be synchronized to the database.

So how can we update person instance in the case of TRANSACTION Persistence Context type?

By merging person instance so that person instance is managed by the database session.

public void update(String name) {
    person = em.merge(person);
    person.setName(name);
    em.flush();
}

The result:


Note: Only the returned object by merge method is associated with the database session.

e.g. if the update method is changed to

public void update(String name) {
    em.merge(person);
    person.setName(name);
    em.flush();
} 

The result:


This is because the above person instance is not managed by database session.