Friday, February 29, 2008

EJB Primer with WSAD - Part 1

This is a step by step tutorial on building a simple EJB application, using Oracle as the BackEnd, primarily for newbies to EJB and WebSphere technologies. We will develop a complete Container Managed (CMP) EJB Application using WSAD - WebSphere Studio Application Developer Version 5.1.2, run and test it on a TestServer in the IDE, and later, package the application to an .ear file and deploy in WebSphere Application Server.


Click on the images to view them full size!



Step 1 - Create the Data Store

Create the table 'employees' with the following columns.

employeeid - number
firstname - varchar(25)
lastname - varchar(25)



Step 2 - Create the EJB and EAR Projects in WSAD

In WSAD file menu, click New->Project->EJB. Create 2.0 EJB Project. Type in the EJB project name as EmployeeEJB and the corresponding EAR project name as EmployeeEAR.





Step 3 - Create the CMP Entity Bean under EmployeeEJB Project

In the J2EE Hirarchy view, right click on EmployeeEJB project, and select New->Enterprise Bean.
Select EmployeeEJB as the EJB Project. In the next window, select CMP as the bean type having version 2.0 and type in the Bean Name as EmployeeEntity, and package name as employee.ejb.




Unselect the Local Client View check box, and Select the Remote Client View checkbox. This is to instruct WSAD to generate the Remote Interface and not to generate the Local Interfaces.
Now, add the persistant fields to the bean. Click the Add button under CMP Attributes and add the fields as below:

employeeid - int
firstname - String
lastname - String

Select 'Promote getter and setter methods to remote interface' to each field except employeeid. For employeeid, select the 'Key Field' option. After adding all fields, click Finish.



Step 4 - Create WebSphere Server

Click on the Server Perspective on the left side bar to open the Projects in the Server Perspective. I the Server configuration Pane, click on Servers->New->Server and Server Configuration.



Give the Server name - TestServer. Make sure that the Server Type is selected as 'Test Enviornment'. In the next page, note the HTTP port on which server would be listening. If you wish to change the port, change it here.




Go to : Part 1Part 2Part 3Part 4Part 5Part 6

Wednesday, February 27, 2008

AJAX in Action

The term AJAX stands for Aynchronous JavaScript and XML. With this new methodology, instead of re-loading a whole browser page after sending a request, using the JavaScript Object XMLHttpRequest will communicate with the server asynchronously to send requests and receive the response. This will allow updating the page, even after the page is loaded, thus making the user stay on the page, and see the changes made on his page, without r-loading the page.

AJAX became popular with the launch of Google Suggest, which uses XMLHttpRequest dynamically suggest the user with search keywords.

Using XMLHttpRequest

IE uses an Activex component called Msxml2.XMLHTTP to generate XMLHttpRequest objects, while browsers like Mozilla, Opera and Netscape uses the JavaScript XMLHttpRequest object.

We need to create an XMLHttpRequest object to hold the request and despatch it to the server.
We also need to define a method, that receivess the response from the server. This is done by assigning the onreadystatechange property with the javascript function that will receive the response.

There is a readyState property, which represents the status of the server response. Each time the state is changes, the function defined in onreadystatechange will be invoked.

Here are the different ready states

0 - Request Uninitialized
1 - Request Initialized
2 - Request Sent
3 - Request Delivered
4 - Response Received


The responseText property is used to retrieve the response sent back from the server.

Here is a small AJAX based JSP Shopping Cart Application. The user is permitted to add and remove items to the shopping cart, from the list of available items.

Each request to add or remove an item creates a new XMLHttpRequest object having the onreadystatechange property set to getReadyStateHandler function, and then posted to the web server.



function addToCart(itemCode) {

var req = newXMLHttpRequest();

req.onreadystatechange = getReadyStateHandler(req, updateCart);

req.open("POST", "cart.do", true);
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("action=add&item="+itemCode);
}

function removeFromCart(itemCode) {

var req = newXMLHttpRequest();

req.onreadystatechange = getReadyStateHandler(req, updateCart);

req.open("POST", "cart.do", true);
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("action=remove&item="+itemCode);
}


The getReadyStateHandler function checks the ready states, and if a response is received, checks the response code, and if it is an HTML status code 200, extracts the response from XMLHttpRequest and designates the javascript updateCart function to handle the response.


function getReadyStateHandler(req, responseXmlHandler) {

// Return an anonymous function that listens to the XMLHttpRequest instance
return function () {

// If the request's status is "complete"
if (req.readyState == 4) {

// Check that we received a successful response from the server
if (req.status == 200) {

// Pass the XML payload of the response to the handler function.
responseXmlHandler(req.responseXML);

} else {

// An Error occurred
alert("HTTP error "+req.status+": "+req.statusText);
}
}
}
}

The updateCart function takes in the response as the input parametar and updates - adds or removes items - in an unordered list - <ul> identified by the name "contents"


function updateCart(cartXML) {
var cart = cartXML.getElementsByTagName("cart")[0];
var generated = cart.getAttribute("generated");
if (generated > lastCartUpdate) {
lastCartUpdate = generated;
var contents = document.getElementById("contents");
contents.innerHTML = "";

var items = cart.getElementsByTagName("item");
for (var I = 0 ; I < items.length ; I++) {

var item = items[I];
var name = item.getElementsByTagName("name")[0].firstChild.nodeValue;
var quantity = item.getElementsByTagName("quantity")[0].firstChild.nodeValue;

var listItem = document.createElement("li");
listItem.appendChild(document.createTextNode(name+" x "+quantity));
contents.appendChild(listItem);
}

}

document.getElementById("total").innerHTML = cart.getAttribute("total");
}


The complete example package can be downloaded from here. Copy the war file to the webapps directory of your Apache Tomcat installation. This will be unpacked automatically in Tomcat.(You may use any other web server as the case may be). In your browser, type in the url: http://localhost:8080/AjaxTest to see AJAX in Action.

Tuesday, February 26, 2008

Log4j and the Art of Logging

Log4j has evolved as the preferred logging mechanism for java developers now. This post is for those who are new to logging using log4j.

As you know, log4j is an Open Source logging API from Apache. The current stable version is 1.2.1.5. You must download the log4j1.2.1.5 jar and add it to your classpath to work with the log4j APIs.

Log4j uses external configuration files. This can be either a log4j.properties file or log4j.xml file, which should be available in the classpath for log4j to work.

The basic building blocks of log4j are called Loggers(or Categories in versions prior to 1.2). The loggers receives log requests from Applications, and forwards these requests to appropriate destinations(called appenders) like console, files etc. The appenders will print the log statement in a format specified by the Layouts.

Loggers can be assigned Priority Levels - DEBUG, INFO, WARN, ERROR or FATAL. This is in ascending order of Priority levels. A logger will only print those statements directed to it, which has a priority greater than or equal to its assigned priority.

A logger will also be configured to use an Appender. This is where you specify the kind of destination, the file path, and any other parametsrs.

A root logger always exists which can be accessed from the application using the getRootLogger() static method of the Logger class. This has a default priority level of DEBUG, unless otherwise specified. All other loggers inherits the properties of root logger unless specified explicitly.

Appenders Can have Layouts associated with them, which specifies the format of a log entry. You can choose from the available Layouts like SimpleLayout, PatternLayout, HTMLLayout, dateLayout etc, or create your own. SimpleLayout prints the logs message along with the Log Level.
PatternLayout depends on a Conversion Pattern, to format the string. This pattern is like the pattern argument of the format() method of JDK 1.5 or the printf statement in C. Like in these methods, we can configure any static text that needs to be printed in the messages.

Here is a sample Conversion Pattern.

"%d{dd MMM yyyy HH:mm:ss} %-5p [%C{1}] {%t} %m"

%d{dd MMM yyyy HH:mm:ss} - Date in dd MMM yyyy HH:mm:ss format
%-5p - Priority of the Log Message
[%C{1}] - Name of the class from which the message is logged in square brackets
{%t} - Name of the thread that generated the log in curly brackets
%m - The log message from the application


Putting it all together, here is a sample log4j.xml file, with two loggers, each having their own Appenders.

The Struts Action class below, makes use of this XML file to log info and error messages to two differet files.
Make sure that the log4j.xml and the log4j1.2.1.5.jar(or any new version) are available in your classpath, before running this sample.




package com.classic.account.action;


import org.apache.log4j.Logger;
import org.apache.struts.action.*;
import javax.servlet.http.*;
import javax.servlet.*;

import com.classic.account.db.*;
import com.classic.account.util.*;
import com.classic.account.forms.*;

public class LoginAction extends Action
{
public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response) throws Exception
{

Logger errlog = Logger.getLogger("ClassicErrors");
Logger inflog = Logger.getLogger("ClassicInfo");
inflog.info("Starting User Authentication");
LoginForm lForm = (LoginForm)form;
String userId = lForm.getUserId();
String password = lForm.getPassword();
String userRole = lForm.getUserRole();
ActionErrors actionErrors = null;
try
{
User user = AccountDAO.getDAO().getUserAuthentication(userId);
if(user == null)
{
actionErrors = new ActionErrors();
actionErrors.add("GlblErrMsg", new ActionError("auth.failure"));
saveErrors(request,actionErrors);
inflog.info("Username Not Specified");
return mapping.findForward("failure");
}
else
{
String retPassword = user.getPassword();
if(!retPassword.equals(MD5Encrypt.getInstance().encrypt(password.trim())))
{
actionErrors = new ActionErrors();
actionErrors.add("GlblErrMsg", new ActionError("global.error"));
actionErrors.add("InvPasWd", new ActionError("password.failure"));
inflog.info("Invalid Password");
saveErrors(request,actionErrors);
return mapping.findForward("failure");
}
else
{
String retRoles = user.getUserRoles();
if(retRoles.indexOf(userRole) == -1 )
{
actionErrors = new ActionErrors();
actionErrors.add("GlblErrMsg", new ActionError("global.error"));
actionErrors.add("InvUsrRole", new ActionError("role.failure"));
inflog.info("User Role Mismatch");
saveErrors(request,actionErrors);
return mapping.findForward("failure");

}
else
{
//Success
request.getSession().setAttribute("AuthUser", user);
request.getSession().setAttribute("UserRole", userRole);
inflog.info("Authenticated Successfully!");
return mapping.findForward("success");
}
}
}
}
catch (Exception e)
{
actionErrors = new ActionErrors();
actionErrors.add("GlblErrMsg", new ActionError("exception.occurred"));
saveErrors(request,actionErrors);
errlog.error("Exception Occurred while Authenticating User.");
return mapping.findForward("failure");
}

}
public LoginAction()
{
super();
}
}


On execution of this class, two files - ClassicInf.log and ClassicErr.log will get created under D:/jakarta-tomcat-5.0.28/logs directory.

On a successful login attempt, the file ClassicInf.log will contain the following lines:

2008-02-26 10:42:17,122 21609 INFO [LoginAction] {http-8091-Processor24} Starting User Authentication
2008-02-26 10:42:17,231 21718 INFO [LoginAction] {http-8091-Processor24} Authenticated Successfully!

In case of an exception, the file ClassicErr.log will have this:

2008-02-26 10:47:23,412 21834 ERROR [LoginAction] {http-8091-Processor24} Exception Occurred while Authenticating User.

Sunday, February 24, 2008

Jakarta Commons HttpClient

Ever wondered how to set a timeout of your choice in a java client application that communicates to a server side component?

You cannot use java.net.URLConnection in this case, because URLConnection doesnot support timeouts.

The solution is to use the Open source Jakarta Commons HttpClient API.
This is a robust API in terms of functionalities including cookie handling, secure communication(SSL), various authentication mechanisms, connection over a proxy etc.
It implements HTTP 1.0 and 1.1 and supports all HTTP methods.

Here is a sample code that submits a form data over a Post method, and prints the response. Instead of waiting indefenitely, the request will timeout after waiting for response after 10 seconds.


package jims;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.httpclient.params.HttpMethodParams;

import java.io.*;
import java.net.SocketTimeoutException;

public class TimeOutTest {

private static String url = "http://localhost:8091/Classic/login.do";

public static void main(String[] args) {
//Instantiate the HttpClient and PostMethod
HttpClient client = new HttpClient();
HttpMethod method = new PostMethod(url);
//or GetMethod(url) as the case may be
try {
//Sets the Retry Handler. This will try to resend the request upto 3 times.
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false));
//Sets the Timeout value - in milliseconds
method.getParams().setSoTimeout(10000);
//Sets the form data - Key value Pairs
NameValuePair form_data [] = new NameValuePair[3];
form_data [0]= new NameValuePair("userId","yyyyy");
form_data [1]= new NameValuePair("password","xxxxxx");
form_data [2]= new NameValuePair("userRole","ZZZZZ");
method.setQueryString(form_data);
//Execute the Method
System.out.println("START:"+System.currentTimeMillis());

//Check the Response Code and print response
int statusCode = client.executeMethod(method);

if (statusCode != 200) //SC_OK
{
System.err.println("Error Occurred: " + method.getStatusLine());
}

byte[] responseBody = method.getResponseBody();

System.out.println(new String(responseBody));

}
catch (HttpException e)
{
System.err.println("Fatal protocol violation: " + e.getMessage());
}
catch (SocketTimeoutException e)
{
System.err.println("Request Timed Out!");
System.out.println("END:"+System.currentTimeMillis());
}
catch(Exception e)
{
e.printStackTrace();
}
finally {
//Finally, release the Connection
method.releaseConnection();
}
}
}


Please note that the socket timeout can be set at multiple layers of the request. It can be set at the method level(which we just experimented). It can also be set at the Connection level and the ConnectionManager level. Refer the Apache Commons HttpClient API Documentation for more information.

You need to have commons-httpclient-3.1.jar added to your classpath before running this example. Download the ZIP file, extract the jar and add it in the classpath.

You might have to download and add to classpath Apache Commons Logging and Commons Codec Jars if they are not there already, as the HttpClient API has dependancy on these two.