Saturday, October 29, 2005

JSF-Database Demo

JSF-Database Demo

Well it has been a hot topic now people talking about `JavaServer Faces`, and there are a few implementation (RI) of `JSR-000127` (e.g.: MyFaces, JSF).

Ingredients
- JSF(JSR-000127) RI (MyFaces / Tomahawk) 1.1.0
- Server/Servlet Container (Apache Tomcat 5.5)
- Java Developement Kit (JDK 5.0)

Introduction
The reason I picked MyFaces instead of pure JSF is because I'm
using Apache Tomcat as my Servlet Container, but that isn't the main
reason; its because MyFaces had lots more cool UI to pick from than the
official JSF RI (e.g.: Calendar, WSIWYG Editor, Menu, Tree, ...)!

So what is so great about the concept? I will describe it as a
web-based Swing (for those who code in Java desktop b4, you should be
familiar with the swing package)!

JSF is really a technology to separate presentation layer from logic layer, and the content developer need not know programming at all (or at least only know how to use which JavaBean).
Installation
I'm assuming that you are using Windows XP as your developement environment.
- download MyFaces 1.1.0
- download Apache Tomcat 5.5
- go here to download JDK 5.0 (it was JDK 5.0 Update 5 by the time I'm writing this)

When you have all the ingredients ready, install them by following the official guide or my simple steps(windows only):
(1)Installing JDK
- Start installation by excuting the file `jdk-1_5_0_05-windows-i586-p.exe`, choose the path `c:\dev\jdk5` when it ask you `Where to install JDK?`; for the JVM just leave by the default path!
- Second thing to do is to set the environment variable for the JDK:
- right click on `My Computer`->choose `Properties`->click on `Advance` tab->click `Environment Variables` on the lower left->create a new variable name by clicking `New` under section `User variables for xxx`)->put `Variable name` as `JAVA_HOME` put the `Variable value` as `c:\dev\jdk5`->click `Ok` ... `Ok` all the way back
- To make compilation and execution java application easier, create a new entry for Windows to lookup java, edit the `PATH` variable by appending `;c:\dev\jdk5\bin`
- Test the instalation by keying in echo %JAVA_HOME% in command prompt, and you should get this: `c:\dev\jdk5`
- Further test the java command by using java in command prompt, and you should get something like this:

Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_04-b05)
Java HotSpot(TM) Client VM (build 1.5.0_04-b05, mixed mode, sharing)


- Done!
(2)Installing Tomcat
- official guide to install tomcat
- unzip the file `apache-tomcat-5.5.12.zip` to directory `c:\dev\`, and you will get something like `c:\dev\apache-tomcat-5.5.12`. Rename it to `c:\dev\tomcat`.
- Set your environment variables `CATALINA_HOME` and `CATALINA_BASE` to `c:\dev\tomcat`.
- To make server startup/shutdown easier, create a new entry for Windows to lookup tomcat, edit the `PATH` variable by appending `;c:\dev\tomcat\bin`

- To start your server, type `startup.bat` in command prompt, and you should see some message like below and a command prompt will popup:

Using CATALINA_BASE: E:\dev\tomcat
Using CATALINA_HOME: E:\dev\tomcat
Using CATALINA_TMPDIR: E:\dev\tomcat\temp
Using JAVA_HOME: C:\Program Files\Java\jdk1.5.0_04


- Navigate your server by pointing you browser to `http://localhost:8080`
- To shutdown your server, type `shutdown.bat` in command prompt, and you should see same message as well and the popup should be close by itself after a while.
- Done!
(3)Installing MyFaces - A dataTable Example
Extract `myfaces-1.1.0.zip` to any directory
(e.g.:C:\dev\myfaces-1.1.0) for javadoc reference. For real
development, download the example package -
`myfaces-1.1.1RC2-examples.zip` and unzip it to `C:\dev\myfaces-1.1.1RC2-examples`. You will find some examples web applications like `simple.war`,`blank.war`, and so on, extract `blank.war` into `C:\dev\myfaces-1.1.1RC2-examples\blank` using Winrar or similar software. Now copy all the jars files from `C:\dev\myfaces-1.1.1RC2-examples\blank\WEB-INF\lib`
to your web application's library directory(e.g.:
C:\dev\tomcat\webapps\myfaces-demo\WEB-INF\lib)). To follow my tutorial
and avoid confusion, just create a demo web application in tomcat with
the following directory structure:

- C:\dev\tomcat\webapps\myfaces-demo
- C:\dev\tomcat\webapps\myfaces-demo\META-INF
- C:\dev\tomcat\webapps\myfaces-demo\WEB-INF\lib
- C:\dev\tomcat\webapps\myfaces-demo\WEB-INF\classes

Create a `web.xml` file in your `C:\dev\tomcat\webapps\myfaces-demo\WEB-INF` directory, with following content:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<display-name>MyFaces Demo</display-name>
<description>a Myfaces demo page</description>
<context-param>
<param-name>javax.faces.application.CONFIG_FILES</param-name>
<param-value>
/WEB-INF/faces-config.xml
</param-value>
</context-param>
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
<context-param>
<param-name>myfaces_allow_javascript</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>myfaces_pretty_html</param-name>
<param-value>true</param-value>
</context-param>
<!-- Faces Servlet -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Faces Servlet Mapping -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<resoure-ref>
<res-ref-name>jdbc/mysql</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resoure-ref>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>


Now we investigate the line below:

<resoure-ref>
<res-ref-name>jdbc/mysql</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resoure-ref>

Notice that I have registered an resource for the datatbase here
wit h the JNDI=`jdbc/mysql`. Actually we have to create an context of
this before we could use this ... so let's make the configure the
database.

For this example I'm using Mysql as my database, I will not discuss a little on that later when we touched on it.

Now for making a pool of database resources, we have to make a file called `context.xml` in `C:\dev\tomcat\webapps\myfaces-demo\META-INF`
directory. Below is how it should be looking like (Notes: this context
configuration file is for Tomcat 5.0 and above, for others version
please refer to tomcat official site):

<!-- MySQL database context -->
<Context path="/myfaces-demo"
docBase="myfaces-demo"
debug="5"
reloadable="true"
crossContext="true">
<Resource name="jdbc/mysql"
auth="Container"
type="javax.sql.DataSource"
username="root"
password=""
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test"
maxActive="8"
maxIdle="4"/>
</Context>


Once we have that, the database should be working well when you
call from the JNDI. Now there is one more ingredient to add in - the `faces-config.xml`. Refer the following code:

<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd" >
<faces-config>
<!-- managed beans of the simple hello world app -->
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>com.avatar21.bean.UserBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>


We have to code a little java from this point, create a javabean by the name `UserBean.java`.

-> UserBean.java listing:

package com.avatar21.bean;

import java.util.Map;
import java.util.HashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class UserBean{
private Map users = null;
private String email;
private Logger logger = Logger.getLogger("com.portfolio");

// email
public String getEmail(){
return email;
}
public void setEmail(String email){
this.email = email;
}

public Map getUsers(){
if(users==null){
try{
populateAction();
}
catch(SQLException sqlEx){
logger.log(Level.SEVERE, "loginAction", sqlEx);
}
catch(NamingException nameEx){
logger.log(Level.SEVERE, "loginAction", nameEx);
}
finally{
return users;
}
}
return users;
}

public void emailSelected(ValueChangeEvent e) {
FacesContext context = FacesContext.getCurrentInstance();
setEmail((String) e.getNewValue());

context.renderResponse();
}

public void populateAction() throws SQLException, NamingException{
Context ctx = new InitialContext();
if(ctx==null){
throw new NamingException("No initial context");
}

Context envContext = (Context)ctx.lookup("java:/comp/env");
if(envContext==null){
throw new NamingException("No environment context");
}

DataSource ds = (DataSource)envContext.lookup("jdbc/mysql");
if(ds==null){
throw new NamingException("No data source");
}

Connection conn = ds.getConnection();
if(conn==null){
throw new SQLException("No database connection");
}

try{
PreparedStatement newsQuery = conn.prepareStatement(
"SELECT user_name, user_email FROM test.user ORDER BY user_name");

ResultSet result = newsQuery.executeQuery();

if(!result.next()){
return;
}
else{
channels = new HashMap();

while(result.next()){
users.put(result.getString("user_name"),result.getString("user_email"));
}
}
}
finally{
conn.close();
}
}
}

Compile the class and put the `UserBean.class` in `C:\dev\tomcat\webapps\myfaces-demo\WEB-INF\classes\com.avatar21.bean`

Create a load page: `index.html` in `C:\dev\tomcat\webapps\myfaces-demo`

<html>
<head>
<title>Loading Page</title>
<meta http-equiv="Refresh" content="0; URL=index.faces" />
</head>
<body>
<font color="#ff0000">Application starting ...</font>
</body>
</html>

The JSF test file: `testSelectOneMenu.jsp` in `C:\dev\tomcat\webapps\myfaces-demo`

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<html>
<head>
<title>Test selectOneMenu</title>
</head>
<body>
<f:view>
<h:form>
<h:outputText value="#{user.email}" onchange="submit();" immediate="true" valueChangeListener="#{user.emailSelected}"/>
<f:verbatim><br/></f:verbatim>
<h:selectOneMenu value="#{user.email}">
<f:selectItems value="#{user.users}"/>
</h:selectOneMenu>
<h:commandButton value="#{msgs.sync}" action="#{user.populateAction}"/>
</h:form>
</f:view>
</body>
</html>

Now in order to let the code works, create a table named `user` in `test` database, below is the Mysql scripts for doing this.

USE test;

CREATE TABLE test.user(
user_id INT NOT NULL AUTO_INCREMENT,
user_name VARCHAR(255),
user_email VARCHAR(255),
PRIMARY KEY (user_id)
);

It should be up and running by now when you point your browser to `http://localhost:8080/myfaces-demo`!

I have not run this example on my server, please send me some screenshot if you able to run it, Thanks!


By Avatar

ngavarta@gmail.com

4 comments:

Baldev Rawat said...

Hi


I am not able to run this application.

Where is index.jsp file.


In your html you have redirected to index.faces but there is no index.jsp

What to do ?

Unknown said...

Hi thanx Avatar

I am not able to run this application. first of all where is index.jsp file ok leave i changed url in index.html and named it testSelectOneMenu.faces but it was showing some tag missing error so i corrected jsf tag in testSelectOneMenu.jsp file but at the end it was throwing exception

javax.naming.NameNotFoundException: Name jdbc is not bound in this Context

in userbean class it is like this

com.avatar21.bean.UserBean.populateAction(UserBean.java:78)
com.avatar21.bean.UserBean.getUsers(UserBean.java:34)

so please let me knoew what to do,its urgent thanx in advance...

Sunil Dhage said...

Hi Avatar,
I obey that you have wrote an article but totally untested. Neither you have specified where's index.faces nor index.jsp.
You have wrote a method populateXXX() where you are not populating rather reading from db, but db is empty just got created. where's the sql to insert users or code which does this?
I sincerely advice you please dont write just for sake of writing blogs and earn.
Neither you have responded to the comments earlier.

SG said...

Dear Sunil,

To start with, what you are asking for are the most simple things that anyone should be able to manage.

For someone like me (with 10 years in Java development and 3 years in project management), what Avatar has provided seems to be the best simple Quick Start example to get you up and running with MyFaces, MySQL and Tomcat with least of the problems.

May be you lack the basic skill set to use this helpful article? May be you can extend this one with the missing things? At least be a bit thankful instead of claiming sutpid stuff about the author.

Thanks and regards,

SSG