• Enter Slide 1 Title Here

    This is slide 1 description. Go to Edit HTML of your blogger blog. Find these sentences. You can replace these sentences with your own words.

  • Enter Slide 2 Title Here

    This is slide 2 description. Go to Edit HTML of your blogger blog. Find these sentences. You can replace these sentences with your own words.

  • Enter Slide 3 Title Here

    This is slide 3 description. Go to Edit HTML of your blogger blog. Find these sentences. You can replace these sentences with your own words.

Showing posts with label Web application. Show all posts
Showing posts with label Web application. Show all posts

Tuesday, September 19, 2017

Transfer domain to namecheap in 2 steps


Transferring domains from any registrar to namecheap is quite simple and straightforward and involves only 2 steps. I am writing this to express how happy I am, on my digizol.com domain transfer experience. Before looking at the steps, let's check motivational factors behind my decision on transferring the domain to namecheap.

Motivations for namecheap

I had few motivations compared to my previous domain registrar.
  1. Ease of use & great customer service rumor
    • Yes, this rumor proved true in my transfer experience
  2. Username is my email address
    • Seriously! my previous domain registrar used a 7 digit number to identify me & I could never remember it. I believe it to be a security feature, but I am not happy with that approach.
  3. Originally paid remaining period is carried forward
    • For my transfer, the expiry date was set including the remaining duration in previous registra. Read more details here
  4. Namecheap promotions for transfers
    • With that, the cost is $ 9.02 at the time I did the transfer
  5. Free Whois protection
    • This is free and saves some money but only for the first year, so I do not count this as a motivation. 

Steps in domain transfer

As mentioned above, this has only two steps.

Step 1 - Follow the straightforward UI

Search for the domain name, click transfer & follow the simple UI. I am not listing down the details as the steps are straightforward.

Step 2 - Chat with online support members

From the point you get stuck or looking for some help, simply use the support. The online chat support is extremely good, I would call it a rockstar. They will stay with you online and do all the needed configurations/changes and instructs on anything to be done on previous registrar's end. You chat will be completed only when everything is in place; at least that is how it ended for me 😄.

Disclaimer: I am not an employee of namecheap.com

Tuesday, July 25, 2017

[Tutorial] Plotly graph drawing in Java webapp - Part 2

Plotly Javascript library supports generating various charts. Java Servlet & JSP based web applications can use it to display graphical representations of data.

In this tutorial, you will learn to include graphs into a simple Java web application. Image above shows the graph generated at the end of the tutorial. Complete project is already moved to github for your references.

This tutorial consists of two parts.

Part 1

First step is to create a simple web application with index.jsp that can submit a user entered parameter to a Servlet which is redirecting the user back to original index.jsp.

Part 2

Here the servlet is modified to return some data (collection of Customer objects) and index.jsp is modified to draw a chart using that data.

Note: If you are not that familiar with Java web applications, I recommend you to start with previous Part 1 of this tutorial before moving further.

Part 2

Java web application project structure in Part 1 must be modified as shown in below image.

Servlet Changes

Servlet class must return a list of Customers to the index.jsp. For that, a simple Customer class and a modification to Servlet is needed.

1. Create a Customer class

This class is used to represent the data send to index.jsp from CustomerServlet. It has an id as well as age & salesCount.

package com.digizol.webapp.plotly;

public class Customer {

private String id;
private int age;
private int salesCount;

public Customer(String id, int age, int salesCount) {
this.id = id;
this.age = age;
this.salesCount = salesCount;
}

public String getId() {
return id;
}
public int getAge() {
return age;
}
public int getSalesCount() {
return salesCount;
}
}

2. CustomerServlet returning Customer object list

doGet() method is modified to return a list of Customer objects. This class has 10 Customer objects. Size of returned list will be based on the 'size' request parameter submitted via index.jsp. This Servlet will return that list as "customersList" to index.jsp.

package com.digizol.webapp.plotly;

import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.*;

public class CustomerServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

System.out.println("Parameter [size] value = " + request.getParameter("size"));
// return a customers list to index.jsp
request.setAttribute("customersList",
getCustomers(resultSize(request.getParameter("size"))));
request.getRequestDispatcher("/index.jsp").forward(request, response);
}

private List<Customer> customers = new ArrayList<Customer>();

public CustomerServlet() {
initCustomersList();
}

private int resultSize(String sizeParam) {
return sizeParam==null?customers.size():Integer.parseInt(sizeParam);
}

private List<Customer> getCustomers(int size) {
return customers.subList(0, size);
}

private void initCustomersList() {
customers.add(new Customer("cust-1", 25, 17));
customers.add(new Customer("cust-2", 36, 99));
customers.add(new Customer("cust-3", 17, 0));
customers.add(new Customer("cust-4", 58, 10));
customers.add(new Customer("cust-5", 49, 32));
customers.add(new Customer("cust-6", 80, 14));
customers.add(new Customer("cust-7", 31, 78));
customers.add(new Customer("cust-8", 22, 89));
customers.add(new Customer("cust-9", 43, 21));
customers.add(new Customer("cust-10", 74, 45));
}
}

3. Get plotly javascript

Download the plotly-latest.min.js Javascript file from here. Place this file under src/main/webapp/plotly/js directory as shown in image.

4. index.js Changes

index.js file needs below changes.

1. Add plotly javascript file to index.jsp
2. Javascript function to draw chart
3. Add a DIV for chart
4. Update index.jsp to organize data for Javascript
5. Update index.jsp to draw chart

Fully completed index.jsp page code looks as below, do not worry. Each change is explained in details after the code.

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>

<head>
<title>Customer Information Center</title>
<script src="plotly/js/plotly-latest.min.js" type="text/javascript"></script>

<script type="text/javascript">
function plotChart(elementId, data, layout) {
Plotly.newPlot(document.getElementById(elementId),
data, layout, {displayModeBar: false});
}
</script>
</head>

<body>

<div style="background:#ffffee; text-align:center; padding-bottom:2px">
<h1>Customer Information Center</h1>

Draw customer information graph.<p/>

<form action="customers" method="get">

Results size:
<select name="size">
<option value="5">5</option>
<option value="10">10</option>
</select>
<p/>
<button style="padding:5px">Draw Chart</button>
</form>
</div>

<c:if test="${not empty customersList}">

<h2>Age and Sales Count Chart</h2>

<div id="customersChart" ></div>

<script>

var customerAges = {
name: 'Age',
type: 'lines+markers',
line: { width: 6},
marker: { size: 8}
};
var customerSalesCount = {
name: 'Sales Count',
type: 'lines+markers',
line: { width: 3},
marker: { size: 4}
};
var age_X = new Array();
var age_Y = new Array();
var sales_count_X = new Array();
var sales_count_Y = new Array();

<c:forEach items="${customersList}" var="customer" varStatus="i">
age_X[${i.index}] = "${customer.id}";
age_Y[${i.index}] = "${customer.age}";

sales_count_X[${i.index}] = "${customer.id}";
sales_count_Y[${i.index}] = "${customer.salesCount}";
</c:forEach>

customerAges.x = age_X;
customerAges.y = age_Y;

customerSalesCount.x = sales_count_X;
customerSalesCount.y = sales_count_Y;

var data = [customerAges, customerSalesCount];
var layout = {
xaxis: {
title: 'ID',
showgrid: true,
zeroline: true,
},
yaxis: {
showgrid: true,
showline: true,
zeroline: true,
}
};

plotChart("customersChart", data, layout);
</script>
</c:if>

</body>
</html>
Each change has a specific reason.

1. Add plotly javascript file to index.jsp

A reference to plotly Javascript file is placed within <head> tags of index.jsp as below.

<head>
<title>Customer Information Center</title>
<script src="plotly/js/plotly-latest.min.js" type="text/javascript"></script>
</head>
2. Javascript function to draw chart
Write a simple function named "plotChart" to draw graphs using plotly as follows inside <head> tag of index.jsp

<head>
<title>Customer Information Center</title>
<script src="plotly/js/plotly-latest.min.js" type="text/javascript"></script>

<script type="text/javascript">
function plotChart(elementId, data, layout) {
Plotly.newPlot(document.getElementById(elementId),
data, layout, {displayModeBar: false});
}
</script>
</head>
3. Add a DIV for chart

It is required to provide an empty DIV element for plotly to generate the chart.

<div id="customersChart" ></div>
4. Update index.jsp to organize data for Javascript
index.jsp page must iterate through the list of Customer objects returns from CustomerServlet as "customersList". Then, Javascript objects must be populated using that data in order to generate the graphs.

As Customer has two attributes age & salesCount, it is possible to draw two lines in one chart. As shown below, x & y properties of customerAges and customerSalesCount must be populated correctly.

var customerAges = {
name: 'Age',
type: 'lines+markers'
};
var customerSalesCount = {
name: 'Sales Count',
type: 'lines+markers',
};
var age_X = new Array();
var age_Y = new Array();
var sales_count_X = new Array();
var sales_count_Y = new Array();


age_X[${i.index}] = "${customer.id}";
age_Y[${i.index}] = "${customer.age}";

sales_count_X[${i.index}] = "${customer.id}";
sales_count_Y[${i.index}] = "${customer.salesCount}";


customerAges.x = age_X;
customerAges.y = age_Y;

customerSalesCount.x = sales_count_X;
customerSalesCount.y = sales_count_Y;
5. Update index.jsp to draw chart

Using customerAges & customerSalesCount Javascript objects, invoke plotChart() method to generate a chart inside "customersChart" div.

var data = [customerAges, customerSalesCount];
var layout = {
xaxis: {
title: 'ID'
},
yaxis: {
showgrid: true
}
};

plotChart("customersChart", data, layout);

Final Result

Below is the final outcome of the application after building & deploying. It shows two line graphs, for age and sales count.



Hope this helps.

Draw graphs in Java webapp with Plotly - Tutorial

Plotly Javascript library supports generating various charts. Java Servlet & JSP based web applications can use it to display graphical representations of data.

In this tutorial, you will learn to include graphs into a simple Java web application. Image above shows the graph generated at the end of the tutorial. Complete project is already moved to github for your references.

This tutorial consists of two parts.

Part 1

First step is to create a simple web application with index.jsp that can submit a user entered parameter to a Servlet which is redirecting the user back to original index.jsp.

Part 2

Here the above servlet is modified to return some data (collection of Customer objects) and index.jsp is modified to draw a chart using those data.

Note: If you are familiar with Java web applications, you can jump to Part 2 directly.

Part 1

1. Build a simple web application

This project contains only one JSP page and a Servlet. JSP is used to display a form & a chart while the Servlet is used to generate raw data for the chart.

First create the Java web application project structure as shown in image.

An index.jsp and a CustomerServlet with web.xml for a simple web application. It also has a pom.xml for the build.

CustomerServlet

doGet() method prints the size parameter in the request; then forwards the request to index.jsp page.

package com.digizol.webapp.plotly;

import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;

public class CustomerServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

System.out.println("Parameter [size] value = " + request.getParameter("size"));
request.getRequestDispatcher("/index.jsp").forward(request, response);
}
}

web.xml

This is the file that configures Servlet related information. Here URL "/customers" is mapped to CustomerServlet.

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

<servlet>
<servlet-name>customers</servlet-name>
<servlet-class>com.digizol.webapp.plotly.CustomerServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>customers</servlet-name>
<url-pattern>/customers</url-pattern>
</servlet-mapping>

</web-app>

index.jsp

This has the ability to submit the results size to "/customers" URL which actually is received by CustomerServlet.

<html>
<body>
<div>
<h1>Customer Information Center</h1>
Draw customer information graph.<p/>
<form action="customers" method="get">
Results size:
<select name="size">
<option value="5">5</option>
<option value="10">10</option>
</select>
<p/>
<button style="padding:5px">Draw Chart</button>
</form>
</div>
</body>
</html>
Clicking on "Draw Chart" button caused the doGet() method to be invoked on CustomerServlet.

pom.xml

Maven build file is used to generate the WAR file including the libraries.

<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>com.digizol.webapp.plotly</groupId>
<artifactId>webapp-with-plotly</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>webapp-with-plotly maven webapp</name>

<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>

<build>
<finalName>customers-plotly</finalName>
</build>

</project>

2. Build & Deploy

With Maven 3.*, you can build the project using "mvn clean package" command. Deployable customers-plotly.war is generated inside target folder.

Copy customers-plotly.war into webapps directory of a Tomcat deployment and start Tomcat server.

Use below URL to see the web page & try clicking "Draw Chart" button.

http://localhost:8080/customers-plotly



Adding charts to this webpage is covered in Part 2.

Thursday, June 28, 2012

Http basic authentication header: Learn with Java code sample

HTTP basic authentication with headers is one of the username & password based methods of securing access to web sites, web applications and web services. Purpose of this article is to analyze the details of this approach by explaining how to encode a pair of username & password as a basic authentication header string as well as to decode the authentication string generated from the web clients like browser or soapIU; and the example is implemented with Java.

Isn't username and password send to server?

When username and password is entered into the pop-up in Web browser (or by similar manner in other web clients) those are not send to server as they are, but send after encoding in a way that the receiving server side can decode and extract the username and password to check the validity. This encoding approach is not secure as the encryption approaches like AES.

Sample request with basic authentication header for username="Aladdin" and password="open sesame" looks as below.

GET /myweb/index.html HTTP/1.1
Host: localhost
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Web clients create a string by concatenating the username and password with a colon (":") as username:password. Then it is encoded in base 64 and is sent to the server, so that the server can do the reverse to extract username and password.

Example Program

Code example imports a class named Imported class named org.apache.commons.codec.binary.Base64 from commons-codec-1.6 available at http://commons.apache.org/codec/download_codec.cgi. Please download it yourself and add the commons-codec-1.6.jar file to the CLASSPATH.

package org.kamal.http.basicauth;

import org.apache.commons.codec.binary.Base64;

public class HttpBasicAuthenticationHeader {

public static void main(String[] args) {

final String username = "Aladdin";
final String password = "open sesame";

System.out.println("Input\t: username [" + username + "], password [" + password + "]");

final String encodedText = createEncodedText(username, password);
System.out.println("Encoded Text : " + encodedText);

final String[] userDetails = decode(encodedText);
System.out.println("Decoded\t: username [" + userDetails[0] + "], password [" + userDetails[1] + "]");

}

private static String[] decode(final String encodedString) {
final byte[] decodedBytes = Base64.decodeBase64(encodedString.getBytes());
final String pair = new String(decodedBytes);
final String[] userDetails = pair.split(":", 2);
return userDetails;
}

private static String createEncodedText(final String username, final String password) {
final String pair = username + ":" + password;
final byte[] encodedBytes = Base64.encodeBase64(pair.getBytes());
return new String(encodedBytes);
}

Output of the program:

Input : username [Aladdin], password [open sesame]
Encoded Text : QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Decoded : username [Aladdin], password [open sesame]

As you can see the above program can encode and decode as expected.

Constraints

As per the related RFC (http://www.ietf.org/rfc/rfc2617.txt); username can not contain any colons, but password has no such restrictions. So it is easy to select the username by splitting the string till the first colon is reached.

Risk involved

This encoded string is passed to the server in plain text. Even though the username and password are hidden in a way; as you may have already guessed, it is not safe at all to use http basic authentication as decoding is straightforward and quite simple. So when ever this approach is used, it is advised to use a secure channel like HTTPS rather than HTTP.

Wednesday, October 27, 2010

[Tomcat] How to change default JSESSIONID cookie/parameter identifier

Changing default JSESSIONID name of cookie and/or parameter is the objective. Deployed J2EE web applications use browser cookie or parameter based session management technique. By default session cookie name is defined as “JSESSIONID” and session id parameter as “jsessionid” in Apache Tomcat servers. These names can be renamed by specifying required values for correct system properties.

Requirements

This system properties based feature is only available in releases newer than Tomcat 5.5.28 and Tomcat 6.0.20.

System properties

Related system properties are;
  • org.apache.catalina.SESSION_COOKIE_NAME (for cookie name)
  • org.apache.catalina.SESSION_PARAMETER_NAME (for parameter name)

Passing system properties

System property can be passed using standard methodology; use “-D” parameter of Java command similar to following.
java -D<key>=<value>

Modify catalina.sh to pass system properties

Following extract is from a modified bin/catalina.sh to pass these system properties; similarly bin/catalina.bat can be modified for Windows based installations.

#!/bin/sh
# // .....
# ------------------------------------------
# Start/Stop Script for the CATALINA Server
# // .....
# ------------------------------------------
JAVA_OPTS="$JAVA_OPTS
-Dorg.apache.catalina.SESSION_COOKIE_NAME=MYJSESSIONID
-Dorg.apache.catalina.SESSION_PARAMETER_NAME=myjsessionid"
# // .....
Note:
The decision on whether cookie based or parameter based session management is used depend on client browser settings.

Related Articles

Tuesday, July 28, 2009

[Ant] Build .WAR files in Eclipse for Web Applications

Eclipse JEE versions support Java Web Application projects, but other Eclipse versions do not. Java developers need to build WAR (web archive) files for deployments (yes, Exploded deployments are also possible). However Eclipse does not provide a direct way to create war files; developers write ant build files for this. So we thought of sharing a generic ant build file for Web Applications.

Our general Web Application's folder structure is shown in the image. In most cases, this structure will exactly match t your project structure; however the folder named "WebRoot" may be different to yours. (If your folder structure is different, let us know in comments section).

Ant Build file (build.xml)

Following is the general ant build file (build.xml).

<project name="MyWebApplication" basedir="." default="archive">

<property name="WEB-INF" value="${basedir}/WebRoot/WEB-INF" />
<property name="OUT" value="${basedir}/out" />
<property name="WAR_FILE_NAME" value="mywebapplication.war" />
<property name="TEMP" value="${basedir}/temp" />

<target name="help">
<echo>
--------------------------------------------------
compile - Compile
archive - Generate WAR file
--------------------------------------------------
</echo>
</target>

<target name="init">
<delete dir="${WEB-INF}/classes" />
<mkdir dir="${WEB-INF}/classes" />
</target>

<target name="compile" depends="init">
<javac srcdir="${basedir}/src"
destdir="${WEB-INF}/classes"
classpathref="libs">
</javac>
</target>

<target name="archive" depends="compile">
<delete dir="${OUT}" />
<mkdir dir="${OUT}" />
<delete dir="${TEMP}" />
<mkdir dir="${TEMP}" />
<copy todir="${TEMP}" >
<fileset dir="${basedir}/WebRoot">
</fileset>
</copy>
<move file="${TEMP}/log4j.properties"
todir="${TEMP}/WEB-INF/classes" />
<war destfile="${OUT}/${WAR_FILE_NAME}"
basedir="${TEMP}"
compress="true"
webxml="${TEMP}/WEB-INF/web.xml" />
<delete dir="${TEMP}" />
</target>

<path id="libs">
<fileset includes="*.jar" dir="${WEB-INF}/lib" />
</path>

</project>

You can go through the above xml file and see the process; we have created an attribute for WAR file's name.

<property name="WAR_FILE_NAME" value="mywebapplication.war" />

You should change the value "mywebproject.war" to match your project name. Save the above build.xml file inside Web applications project folder as shown in the folder structure image.

Ant build file has separate tasks for compiling the project and to build the war file. In Eclipse you just have to right click on this build file and select "Ant Build" to execute it. The war file will be generated and stored inside <web-project>/out folder.

Related Articles

How to open a .war (web archive) or .jar (java archive) files
Open and read any file in a .war file of a web application with Java

Thursday, July 9, 2009

[Tomcat] validateJarFile(servlet-api.jar) - jar not loaded. Offending class: javax/servlet/Servlet.class

validateJarFile jar not loadedorg.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(<APP_PATH>\WEB-INF\lib\servlet-api.jar) - jar not loaded. See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class
.

We are using Apache Tomcat to deploy web applications, and getting the above message when Apache Tomcat is started. All web applications inside Tomcat are working fine, however no developer would want to see message (at least we do not want to see).

The above message is only a warning message due to the existence of multiples of the same javax.servler.Servlet.class for Tomcat runtime to pick; and this extra instance has come from a jar file named <APP_PATH>\WEB-INF\lib\servlet-api.jar. Tomcat has its own servlet-api.jar file; look at the following folders to locate the file (depending on the Tomcat version; location may be different).
  • <TOMCAT_HOME>\common\lib
  • <TOMCAT_HOME>\lib
Your web applications have the same servlet-api.jar file inside following folder.
  • <TOMCAT_HOME>\webapps\<PROJECT>\WEB-INF\lib
As the Tomcat runtime has the required javax/servlet/Servlet.class file loaded from its own lib\servlet-api.jar file, you do not need to place it inside each and every web application. After removing the jar file from your web application, you will not receive the message again.

Related Articles

Wednesday, October 15, 2008

Manage HTTP headers with Java Servlets: Quick Notes

Servlet & JSPIn Java Servlets API, both HttpServletRequest and HttpServletResponse interfaces (in javax.servlet.http package) provide methods to programatically manipulate HTTP headers. There are a number of standard HTTP headers exchanged between a web server and a client (eg: a browser). "Content-Type" is a commonly used header (which is used to specify MIME type) in Servlets. In this article we are discussing how headers are read/written with Servlet classes.

Reading Headers

A servlet can read HTTP headers sent by a client request using HttpServletRequest interface. This interface has two methods for this.

String getHeader(String headerName)
int getintHeader(String headerName)

Both these methods are similar except getIntHeader() method is used to return value of headers with int type values. Below code shows how value of "User-Agent" header is read from the user request. (HttpServlet.doGet() method is used in the example).


import javax.servlet.http.*;
import java.io.*;

public class MyServlet extends HttpServlet {
public void doGet(re, res) throws IOException{
String contentType = request.getHeader("Content-type");
....
}
}

Creating/Writing Headers

A servlet can create a header and send back to the client using HttpServletResponse interface; using the following setter methods.

void setHeader(String headerName, String headerValue)
int setintHeader(String headerName, int headerValue)

Below code shows how a new header named "My_Header" is created and set on response.


import javax.servlet.http.*;
import java.io.*;

public class MyServlet extends HttpServlet {
public void doGet(re, res) throws IOException{
response.setHeader("My_Header", "new Header value");
....
}
}

Now the client (generally the browser) will receive this new header.

Tuesday, September 2, 2008

Google Web Toolkit (GWT) & Servlets - Web application tutorial

GWT LogoGoogle Web Toolkit (GWT) and Java Servlets used in one web application. This tutorial will take you though the steps of developing a simple web application with Google Web Toolkit and J2EE Servlet Technology. The application will have a servlet on server side and one web page.

Prerequisites

  • Better to be familiar with developing web applications with J2EE/Servlets
  • Knowledge on deploying a web application into Tomcat web server

System Requirements

  • JDK installed
  • Apache Tomcat web server (download, any other web server can be used)
  • GWT (download)
In brief, GWT is a framework for developing Ajax based web pages with Java. All the HTML page content will be written as Java classes and converted into a set of Javascript files. For more information on GWT, refer to official site here. http://code.google.com/webtoolkit/

Introduction

In this tutorial we will create a simple web application which has one page. When a user clicks a button, web page content will be updated without refreshing or leaving the current page. But the web page will talk to a servlet deployed in web server and update the page content. The communication between web server and browser will be invisible to the user, providing a convenient web experience. Even though this is a simple application, it represents a main concept of any advanced application implemented with GWT.

Implementation

The development work is broken down into 7 steps and each will be discussed in details.
  1. Create a java web project with GWT
  2. Data Service - server & client side
  3. Widget (component displayed on web page)
  4. Entry point
  5. Web page (html/jsp)
  6. Module XML
  7. Compile and deploy
In this document $GWT_HOME is used to denote the directory where extracted GWT framework is available.
eg: $GWT_HOME=C:\java\gwt-windows-1.4.61

1. Create a java web project with GWT

To start with, we need to create a java project. GWT comes with a script to create a java project according to the recommended project structure. It is called "applicationCreator"; applicationCreator.cmd is available inside $GWT_HOME directory.

$GWT_HOME> applicationCreator -out C:/samples/GWT-Sample 
org.kamal.hello.client.HelloWorld

For parameter named "out" you must provide the location to create the new project. Also a class name must be provided for this command. This class is called Entry point class (we'll be touching this class later).
Above command creates a project named GWT-Sample in the destination location and created project would look as follows.

GWT applicationCreator project structureIt will contain a Java class (Entry point class), a HTML page and a XML file (called Module XML). This module xml file will also be discussed later. For the time, better note the path to this file: org/kamal/hello/HelloWorld.gwt.xml.

2. Data Service - server & client side

For our application we need a service that provides data for our client side page. So we'll define this service to have only one method returning a String. This service will be provided through a servlet which is running on a server side. Generally we would write only a single servlet that extends from javax.servlet.http.HttpServlet, but in GWT we must define two interfaces inside client package (org.kamal.hello.client) along with the servlet. However these two interfaces are quite simple.

i). Service interface

The services provided by the server-side must be declared in a Service interface first. The methods declared in the Service interface will be available to the client side. It is only a simple interface which must extend com.google.gwt.user.client.rpc.RemoteService interface. We will define the service interface with only one method that returns a string.

package org.kamal.hello.client;

import com.google.gwt.user.client.rpc.RemoteService;

public interface DataService extends RemoteService {
public String getData();
}

ii). Asynchronous Service interface

Next we will define another interface called "Asynchronous interface". This interface is used to define the asynchronous feature of the service. That is when ever a call is made to this interface, the caller can expect the service to be asynchronous and the result will be available after sometime. The caller must provide a callback object to receive the resulting data. There are some important points to note.
  1. Asynchronous interface must be in the same package as the service interface
  2. This interface's name must be as <Service-Interface-Name>Async (same name with Async suffix)
  3. Add a new parameter of type com.google.gwt.user.client.rpc.AsyncCallback to parameter list of every method.
  4. All methods must have void as return type
package org.kamal.hello.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface DataServiceAsync {
public void getData(AsyncCallback callback);
}

The above interface is named DataServiceAsync (using DataService + Async) and the DataService.getData() method is provided with a new parameter while having void return type.

iii). Service servlet

Now we can define the service servlet which does the actual work. This class must implement above declared DataService interface and extend the com.google.gwt.user.server.rpc.RemoteServiceServlet class.

package org.kamal.hello.server;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import java.util.*;
import org.kamal.hello.client.DataService;

public class DataServiceImpl
extends RemoteServiceServlet implements DataService {

public String getData() {
int key = (int)(Math.random()*3);
return (String)data.get(String.valueOf(key));
}

private static Map data = new HashMap();

static {
data.put("0", "Hi, This is Server");
data.put("1", "How are you?");
data.put("2", "It’s too warm here at Server");
}
}

Above class implements the getData() method of DataService interface and returns a String with simple logic. Even though we call this a servlet, no servlet specific implementation is available, so is this a servlet? Yes, it is; the super class, RemoteServiceServlet is a servlet.

iv). Servlet configuration (web.xml)

Now we have to specify the servlet in a web.xml file. (Do not worry even if you are not much familiar with web.xml, everything needed is listed below).

Create a file named web.xml inside GWT-Sample project folder with the following content.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<servlet>
<servlet-name>DataService</servlet-name>
<servlet-class>
org.kamal.hello.server.DataServiceImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DataService</servlet-name>
<url-pattern>
/org.kamal.hello.HelloWorld/data
</url-pattern>
</servlet-mapping>
</web-app>

Here we have defined a url pattern for our above mentioned DataServiceImpl servlet. Note the way this url pattern (/org.kamal.hello.HelloWorld/data) is defined.
First part of the url pattern org.kamal.hello.HelloWorld is derived from the path to Module XML file which is org/kamal/hello/HelloWorld.gwt.xml. The rest of the url pattern can be selected arbitrarily, better to use a declarative word.

3. Widget (component displayed on web page)

Now we must create the widget that will be displayed in the web page of our web application. The widget coding is listed below.

package org.kamal.hello.client.widgets;

import com.google.gwt.core.client.*;
import com.google.gwt.user.client.rpc.*;
import com.google.gwt.user.client.ui.*;
import org.kamal.hello.client.*;

public class HelloWidget extends Composite {

public HelloWidget() {
// obtain a reference to the service
service = (DataServiceAsync) GWT.create(DataService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) service;
endpoint.setServiceEntryPoint(GWT.getModuleBaseURL() + "data");

initWidget(panel);
panel.add(label, DockPanel.CENTER);
panel.add(button, DockPanel.SOUTH);

// click listener to get data from server
button.addClickListener(new ButtonClickListener());
}

private class ButtonClickListener implements ClickListener {
public void onClick(Widget sender) {
// call servlet to get data
service.getData(new AsyncCallback() {

public void onFailure(Throwable e) {
label.setText("Server call failed");
}
public void onSuccess(Object obj) {
if (obj != null) {
label.setText(obj.toString());
} else {
label.setText("Server call returned nothing");
}
}
});
}
}

private final DataServiceAsync service;
private final DockPanel panel = new DockPanel();
private final Button button = new Button("Talk");
private final Label label = new Label("Welcome, talk to server");
}

This widget contains one label and one button. It uses a reference of type DataServiceAsync to communicate with the DataServiceImpl servlet deployed on a web server. You must pay attention to the way this DataServiceAsync reference is obtained.
HelloWidget.ButtonClickListener class is there to respond to onClick() action of the button. Inside this class an implementation of AsyncCallback is used to get data from the DataServiceAsync reference and to update the label content.

4. Entry point

Entry point class was generated while creating the project at step 1 of this tutorial with the class name org.kamal.hello.client.HelloWorld. This is the class used to load the widget into the web page. Inside the onModuleLoad() method, we have accessed an element named "content"; this element must present in the web page that we are expecting to load the widget. Then the HelloWidget; the widget we created above is added into this element.

package org.kamal.hello.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import org.kamal.hello.client.widgets.HelloWidget;

public class HelloWorld implements EntryPoint {

public void onModuleLoad() {
// set widget on "content" element
RootPanel content = RootPanel.get("content");
if (content != null) {
content.add(new HelloWidget());
}
}
}

5. Web page

Following is the page that we will be using to load our HelloWidget. This page is already available inside GWT-Sample1\src\org\kamal\hello\public folder. Edit this page to have the following coding.
This page contains an element with id="content", which is used to load the newly created widget into this page. Also note that a .js file has been imported into this page. We will be generating this org.kamal.hello.HelloWorld.nocache.js file in a following step.

<html>
<head>
<title>HelloWorld</title>
<script language="javascript"
src="org.kamal.hello.HelloWorld.nocache.js">
</script>
</head>
<body>
<h1>HelloWorld</h1>
<table align="center" width="100%">
<tr>
<td id="content"></td>
</tr>
</table>
</body>
</html>

6. Module XML

This is the module configuration (module xml) file. The entry point class is specified in this module xml. This file is also autogenerated in step 1, and it is stored inside "org\kamal\hello" folder.

<module>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name="com.google.gwt.user.User" />

<!-- Specify the app entry point class. -->
<entry-point class="org.kamal.hello.client.HelloWorld" />
</module>

7. Compile and deploy

We have created all the required classes and files. Now we must generate Javascripts from above created Java classes. Then compile and deploy the project.

i). Generate Javascript from Java classes

For generating Javascript files from Java classes we will use the HelloWorld-compile.cmd, which was generated into the project folder in the step 1. You just have to run this command file without any parameters.

GWT-Sample> HelloWorld-compile.cmd

This will create a new folder named "www" inside GWT-Sample project folder, and it will contain a set of web resources including "org.kamal.hello.HelloWorld.nocache.js" file which we used in step 5.

ii). Compile classes

Now create a folder named "WEB-INF" inside "www" folder. Then create two folders named "classes" and "lib" inside this WEB-INF folder.
Now compile service related Java classes that we created up to now into this www/WEB-INF/classes folder.

GWT-Sample\src> javac -cp $GWT-HOME/gwt-user.jar 
-d ../www/WEB-INF/classes
org/kamal/hello/client/Data*.java
org/kamal/hello/server/*.java

Now copy $GWT-HOME/gwt-servlet.jar file into the www/WEB-INF/lib folder.

GWT-Sample> copy $GWT-HOME\gwt-servlet.jar www\WEB-INF\lib

Note: we use gwt-user.jar to compile while gwt-servlet.jar at deployment. (you can read the reason here).

Copy GWT-Sample/web.xml into www/WEB-INF folder.

iii). Deploy into web server


GWT web application deployed in TomcatCreate a folder named "GWT-Sample" inside $CATALINA_HOME/webapps and copy "www\org.kamal.hello.HelloWorld" and "www\WEB-INF" folders into that "GWT-Sample" folder (shown above). Now everything is completed.

Start Tomcat and try the following URL from your browser.
http://localhost:8080/GWT-Sample/org.kamal.hello.HelloWorld/HelloWorld.html

GWT HelloWorld web application outputNow you will see the web page with the label text and button as shown in the image. Play around by clicking the button to see different messages coming from the server. The web page will not be re-fetched from the web server, but only the text of the label will be refreshed.

Even though this is a pretty simple application, you can use this concept to develop advanced applications.

Wednesday, August 29, 2007

Add css styles for gwt widgets

Adding Cascading styles (CSS) to Google Web Toolkit (GWT) widgets is much simpler and involves only two steps.
  1. Style name
    • set style name
      for a widget using the $widgetInstance$.setStyleName() method or
    • stick with the default
      style name of the widget (use for setting global values)
      default style name examples:
      • for buttons: .gwt-Button
      • for Check Boxs: .gwt-CheckBox

  2. CSS style rule
    • Add CSS style rules to a .css file and import that into the html page or

    • write those inside the html page itself. (not recommended)

Let us provide you with an example which would create buttons shown below.


Coding in your java class:
Button cancelButton = new Button("Cancel");
Button loginButton = new Button("Login");
loginButton.setStyleName("buttons");

CSS rules:
.gwt-button {
background: #EEEEFF;
color: #0000CC;
font-size: 12px;
}

.buttons {
background: #CCCCCC;
color: #333333;
font-size: 12px;
}

Monday, August 13, 2007

Set Cookies with GWT applications to expire after expected time period

Google Web Toolkit (GWT) supports HTTP cookies similar to other web technologies. GWT provides methods for setting cookies for specified time duration, for specific domains and paths. Below is a listing on how to set a basic cookie for a duration of one day.
Date now = new Date();
long nowLong = now.getTime();
nowLong = nowLong + (1000 * 60 * 60 * 24 * 7);//seven days
now.setTime(nowLong);

Cookies.setCookie("sampleCookieName", "sampleCookiValue", now);

When retrieving the cookies, you have to specify only the name of the cookie, nothing related to duration. If the cookie is found in the browser for this domain (not expired); value you set will be returned.
Cookies.getCookie("sampleCookieName");//only name

In setting cookies, you must consider on what you actually plans to get done using a cookie. There are two features you can achieve; remember duration (i)from the day it's created, (ii) from the last day this particular user viewed your site. If your site always set cookies when ever a user visits your site; then your cookies will expire only after the user does not revisit your site for the specified duration. But if you are providing a feature like "Saving the password for 2 weeks", then you probably should store the cookie only if the cookie does not exists. For that you must look for cookie before setting it again.
String sampleValue = Cookies.getCookie("sampleCookieName");
if(sampleValue == null){
//set cookie again after informing user on expiration.}

Thursday, July 19, 2007

Scrollable table with GWT

We came across a requirement to build a scrollable data table using Google Web Toolkit (GWT) because we had a limited space, but a growing table depending on the search criteria. As anyone can guess, having a scrollable table would be the best option. For that we used two components rather than one; com.google.gwt.user.client.ui.ScrollPanel and com.google.gwt.user.client.ui.FlexTable. The data table was added inside the Scrollable Panel.

For clarification, we have added the code below.
ScrollPanel scrollPanel = new ScrollPanel();
FlexTable dataTable = new FlexTable();

dataTable.setWidth("100%");
scrollPanel.add(dataTable);
scrollPanel.setSize("300", "200");

//add data to table
....

For setting width and height; it's advised to use css rules, but for ease of understanding we have shown some hard coded values here.