Showing posts with label GWT. Show all posts
Showing posts with label GWT. Show all posts

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.

java.lang.SecurityException: Blocked attempt to access interface - Issue in GWT 1.4.6 upgrade

Exception while dispatching incoming RPC call
java.lang.SecurityException: Blocked attempt to access interface 'http://localhost/myApp/org.kamal.project.module/', which is either not implemented by this servlet or which doesn't extend RemoteService; this is either misconfiguration or a hack attempt


The GWT application was working fine earlier; so decided to upgrade to the new GWT versio. But!!! with the upgrade, application fail with a Security exception.

Above is an extract from the exception thrown by GWT, while upgrading old GWT application to GWT 1.4.6 version.

Even though SecurityException is thrown, most possible cause for the above error is; old gwt-servlet.jar file has not been replaced with the new gwt-servlet.jar in the server side. (Make sure you replace all the old jar files in a upgrade).

By placing the new gwt-servlet.jar file inside the lib directory on your server, this issue will be resolved.

Complete stack trace would look as below.

- Exception while dispatching incoming RPC call
java.lang.SecurityException: Blocked attempt to access interface 'http://localhost/myApp/org.kamal.project.module/', which is either not implemented by this servlet or which doesn't extend RemoteService; this is either misconfiguration or a hack attempt
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:211)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.doPost(RemoteServiceServlet.java:167)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:619)

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;
}

GWT releases 1.4 and is no longer beta

Google Web Toolkit (GWT) has released a new version, 1.4. With over 1 million downloads GWT is moving forward well; and it's no longer beta. The user group is really active and well established; so if you haven't tried GWT yet, it's time to have a look.

GWT LogoRead more about GWT and news release at GWT blog.

For any issues visit the GWT user group here.

GWT not working on Internet explorer 7 (IE7) giving "Element not found" javascript error

GWT web application started to give "Element not found" javascript error message on Internet Explorer 7 (IE7)? This application worked fine on Internet Explorer 6 and Firefox 2. Now your best guess would be; GWT not working on IE 7 properly. Wasn't it?

But the scenario became confusing and unbelievable because your application worked fine on IE7 in some machines while not on some others. Have you faced this issue? Then the below solution is for you.

This issue can be fixed by a making a change on windows registry.

Steps to follow are;
1. Open up the Registry editor - type regedit on command prompt.

2. Look for the key shown below
HKEY_CLASSES_ROOT\TypeLib\{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}\1.1\0\win32

3. Click on the "Default" row and see the value there. If it's value is "C:\WINDOWS\system32\shdocvw.dll", then that is what causes the above mentioned issue. If you have installed Windows in a different drive; C:\ must be replaced with the that letter.

4. Replace that value with "C:\WINDOWS\system32\ieframe.dll".

5. Now restart IE7, and load your GWT application.

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.}

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.

Jar not loaded warning/error in Google Web Toolkit (GWT) deployment to tomcat

When a Google Web Toolkit (GWT) web application is deployed to Tomcat web server, you may encounter a warning message as follows.
org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(<$webAppsFolder$>\WEB-INF\lib\gwt-user.jar) - jar not loaded.
See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class

No need to worry too much about this warning message. This raises just because WebappClassLoader has loaded the servlet.jar already. The gwt-user.jar already contain the content of the servlet.jar file. Even though this message can be ignored, this warning message can be avoided just by replacing the gwt-user.jar file with gwt-servlet.jar (which comes with Google Web Toolkit (GWT) download).

Following image shows the content of the gwt-user.jar, and the content of the servlet.jar is highlighted.



gwt-servlet.jar has been created by removing the content of the servlet.jar from the gwt-user.jar, so this change will not have any impact on your project.

Check out this stream