Build an Ajax-enabled application using the Google Web ...

unalaskaweepingInternet and Web Development

Jul 19, 2012 (5 years and 2 months ago)

530 views

Build an Ajax-enabled application using the Google
Web Toolkit and Apache Geronimo,Part 2:
Integrate your Ajax apps with a back-end MySQL
database using a servlet
Skill Level:Intermediate
Michael Galpin
Developer
Adomo,Inc.
21 May 2007
In the first part of this tutorial series,you learned how to use the Google Web Toolkit
(GWT) to rapidly build an Asynchronous JavaScript + XML (Ajax)-enabled Web
application and deploy it to Apache Geronimo.In this installment,Part 2 of the
two-part series,you add more functionality to the application that you built in the first
tutorial.Take advantage of Geronimo to add new features to the application by
managing access to a back-end database.Then use GWT to add more dynamic
functionality and easy integration with the new features that the service provides.
Also,take a look at some of the dynamic HTML (DHTML) features of GWT and using
native JavaScript within a GWT application.
Section 1.Before you start
About this series
Ajax-enabled Web applications have become incredibly popular recently.Ajax
makes Web applications behave a lot like desktop applications.They offer greater
interactivity and functionality than the previous generation of Web applications.And
Geronimo provides the perfect platform for building Ajax-enabled Web applications.
However,building Ajax-enabled Web applications is more difficult than building
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 1 of 40
traditional Web applications.It involves lots of JavaScript and Dynamic HTML
(DHTML) development.Quirks among different browsers—and even different
versions of the same browser—further complicate things.The GWT is one of many
Ajax frameworks that makes your job easier by using a novel approach that lets you
write all of your code in the Java language and generates all the JavaScript for you.
The two tutorials in this series cover the following topics:
• Part 1 focused on getting started with GWT and creating a simple
Ajax-enabled Web application for getting stock quotes.
• Part 2,this installment,shows you how to make the stock quotes
application more sophisticated and transform it into a stock portfolio
application using both GWT and Geronimo.
About this tutorial
In the first part of the tutorial series,you built an Ajax-enabled Web application.Now
you're going to expand on this application and use more enterprise features,like
database access.See how GWT lets you use Ajax to make it easy to send
messages to a server,and how Geronimo makes it easy for your server-side
application to update a database asynchronously.
Check out the Ajax Resource Center,your one-stop shop for
information on the Ajax programming model,including articles and
tutorials,discussion forums,blogs,wikis,events,and news.If it's
happening,it's covered here.
In this tutorial,you turn a stock application into a portfolio management application
that:
• Allows your users to get quotes on multiple stocks,thus building a
portfolio.
• Lets users save their portfolios by giving themselves user names.
• Adds the stock to users'portfolios each time they ask for a quote.
• Uses Geronimo to create a pool of connections to that database and then
uses JDBC to read and write to the database.
• Saves the users'names and the stocks in their portfolios in a relational
database.
Prerequisites
This tutorial is about building a Java Web application,but you only need to
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 2 of 40
understand the basics of Java servlets.GWT leverages many ideas common to
other technologies,such as layout management,event systems,and remote
procedural calls (RPCs),so prior exposure to these ideas makes it easy to master
GWT.The tutorial uses SQL and Java Database Connectivity to work with a
relational database,so some familiarity with these tools is helpful.
System requirements
You need the following software to set up your development environment before
getting started:
• Geronimo 2.0 with Tomcat — The sample Web application in this tutorial
was built using Geronimo with Tomcat,but it should also work with
Geronimo with Jetty,because everything is standard Java Platform,
Enterprise Edition (Java EE).This tutorial uses Geronimo 2.0 (M3) but
should work with older versions of Geronimo as well.
• Java 5 or Java 6 — The sample Web application uses generics and
annotations.It was developed using Java 6,but also tested against Java
5.
• Apache Jakarta implementation of JSTL 1.1 — Geronimo 1.1 is a certified
J2EE 1.4 implementation,so you need to use JSTL 1.1.
• Google Web Toolkit — This tutorial is all about the GWT;download GWT
1.3.3 for this tutorial.
• Eclipse — The sample Web application is built using Eclipse,as you'll see
from the screen captures.GWT includes a convenient command-line tool
for creating a skeleton Eclipse project.It's not hard to build GWT
applications without Eclipse,but Eclipse provides a great debugger to
debug your GWT application.
• MySQL 5.0 — The sample application uses MySQL as its database.One
of the great things about Enterprise Java and Geronimo is that you can
easily switch out and use a different database.A great alternative is
Apache Derby,which comes embedded in Geronimo.There were some
bugs with Geronimo using embedded Derby as part of the 2.0
development,so this tutorial uses an external database.
For instructions on downloading and installing GWT,see Part 1 of this series.
Section 2.Overview
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 3 of 40
In this section,you:
• Review the expanded functionality of your stock portfolio application.
• Set up the database.
• Create a database connection pool.
• Make the connection pool available to any application running on
Geronimo.
• Add the connection pool to your portfolio application.
The stock portfolio application
The Ajax-enabled Web application that you built in Part 1 accepted a stock symbol
and then used Ajax to request information about that stock from the server.You
used GWT to generate the client-side code that initiated the request to the server.
The server was Apache Geronimo,of course,running a Java Web application.
Now you're going to turn your stock application into a portfolio-management
application that lets users get quotes on multiple stocks,thus building a portfolio.
Users can then save their portfolios by giving themselves user names.After they're
logged in,each time they ask for a quote,you add the stock to their portfolios.The
user names and stocks saved in the portfolios reside in a relational database.You
use Geronimo to create a pool of connections to that database,and then use JDBC
to read and write to the database.GWT generates all the Ajax calls back to the
server.
The first thing you need to do is set up your database.
Set up the database
JDBC provides a generic interface to common database functionalities.This lets
your application use almost any database that has a JDBC driver for it.For your
application,use MySQL (see System requirements for download information).It's a
popular database,because it's open source and easy to use.
After your database is installed and running,you need to create a schema for it.
Then you need to create two tables.The SQL script in Listing 1 creates the schema
and the tables.
Listing 1.SQL script for creating DB
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 4 of 40
CREATE DATABASE STOCKS;
USE STOCKS;
CREATE TABLE USER (
USER_ID INT NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20) NOT NULL,
PRIMARY KEY(USER_ID)
);
CREATE TABLE PORTFOLIO (
USER_ID INT NOT NULL,
SYMBOL VARCHAR(5) NOT NULL,
FOREIGN KEY (USER_ID) REFERENCES USER (USER_ID)
);
The user table simply stores an ID for the user and the name of the user.If you were
trying to build something more robust,you'd put a password field,capture more user
information,and so on.But only a name will suffice for your portfolio application.
The portfolio table stores multiple stocks associated with a user.Again,a more
robust application might normalize the stocks so that if two users each have IBM® in
their portfolio,it would appear only once.You could then use an association table.
The denormalized schema in Listing 1 is simpler and sufficient for your application.
Now that you have somewhere to store your portfolio data,you need a way to
access and modify this data.That's where Geronimo comes in.
Use Geronimo database connection pools
One of the great features of Geronimo is that you can use it to create a database
connection pool.This pool is then usable by any application running on Geronimo.It
becomes a DataSource object that can be accessed using Java Naming and
Directory Interface (JNDI.) The DataSource can then give you a JDBC connection
that lets you query the database and update the database with new data.
To create a database connection pool,use the Geronimo Console.Typically you can
access that at http://localost:8080.
1.Select Services > Database Pools from the menu,as shown in Figure 1.
Figure 1.Selecting database pools fromthe Geronimo Console
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 5 of 40
This should bring up the list of current database pools,and you should
see the default system ones used by Geronimo for its internal services.
2.Create a new one by selecting Create a new database pool > Using the
Geronimo database pool wizard,as shown in Figure 2.
Figure 2.Selecting the Database Pool wizard
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 6 of 40
This should bring up Step 1 of the Create Database Pool wizard.
3.Call your database pool stocks-db,and select the type of database
from the drop-down list,as shown in Figure 3.
Figure 3.Step 1 of the Create Database Pool wizard
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 7 of 40
4.Click the Next button to bring up Step 2 in the wizard,the Select Driver,
JAR,Parameters panel.The JDBC Driver Class should already be filled
in.
5.You need a JAR file with your driver.You could download this from
MySQL,but Geronimo can actually do this for you.Select the Download
a Driver button,as shown in Figure 4,which brings up the Select Driver
interface.
Figure 4.Step 2 of the wizard:Select Driver,JAR,Parameters
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 8 of 40
6.Select the latest MySQL JDBC driver from the list,then click Next,as
shown in Figure 5.
Figure 5.Select MySQL JDBC driver
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 9 of 40
7.This brings up the Driver Download screen,which shows you the
progress in downloading the MySQL JDBC driver,as shown in Figure 6.
Figure 6.Downloading the MySQL JDBC driver
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 10 of 40
8.After the download completes,you're brought back to the Select Driver,
JAR,Parameters interface.In the Driver JAR field,the JAR file you just
downloaded should be selected.Now fill in the rest of the info on your
database,as shown in Figure 7.
Figure 7.Filling out the driver,JAR,and parameters
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 11 of 40
9.Click Next to bring you to Step 3 in the wizard.
10.Click the Test Connection button,as shown in Figure 8.
Figure 8.Step 3 in the Create Database Pool wizard
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 12 of 40
11.Hopefully the test succeeds.If so,click the Deploy button,as shown in
Figure 9.
Figure 9.Testing connection
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 13 of 40
12.After the database pool is deployed,you're brought back to the list of
database pools.You should see your new stocks-db pool.Click the
usage link for your new database pool,as shown in Figure 10.
Figure 10.The new database pool
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 14 of 40
This should bring up the usage screen (see Figure 11),which contains all
the information you need to add the new database pool to any application,
including your new portfolio application.
Figure 11.Database pool usage
As you can see from the usage,you reference the database pool just like any other
DataSource object in your web.xml file.However,you can manage it a little more
efficiently than a typical JNDI DataSource object,courtesy of Geronimo.Geronimo
deploys the database pool as a connector,and you map the connector to your
DataSource object in the geronimo-web.xml file.These two files are covered in
more detail in the next section,where you add the DataSource object to your
application.
Add the DataSource object to the application
Geronimo made it easy to create a database connection pool for your database.
Now your database connection pool is available to any application running on
Geronimo.All you need to do is add it to your portfolio application.You start to do
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 15 of 40
this by adding it to your geronimo-web.xml file,as shown in Listing 2.
Listing 2.Adding DataSource to geronimo-web.xml
<web-app
xmlns="http://geronimo.apache.org/xml/ns/j2ee/web-1.1">
<environment>
<moduleId>
<artifactId>StocksApplication</artifactId>
</moduleId>
<dependencies>
<dependency>
<groupId>console.dbpool</groupId>
<artifactId>stocks-db</artifactId>
</dependency>
</dependencies>
</environment>
<context-root>/stocks</context-root>
<resource-ref>
<ref-name>jdbc/MyDataSource</ref-name>
<resource-link>stocks-db</resource-link>
</resource-ref>
</web-app>
As mentioned previously,your database pool is deployed as a connector.A
connector is like any module deployed to Geronimo.Your application is also a
module in Geronimo,so you use the geronimo-web.xml file to create a dependency
between your application and the connector module you created for the database
connection pool.You then create an alias for it,so you can use this in your web.xml
file,as shown in Listing 3.
Listing 3.Referencing the DataSource in web.xml
<?xml version="1.0"encoding="UTF-8"?>
<web-app
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"
version="2.4">
<servlet>
<servlet-name>stocksServiceServlet</servlet-name>
<servlet-class>org.developerworks.stocks.server.StocksServiceImpl
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>stocksServiceServlet</servlet-name>
<url-pattern>/stocksService</url-pattern>
</servlet-mapping>
<resource-ref>
<res-ref-name>jdbc/MyDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
<welcome-file-list>
<welcome-file>
StocksApplication.html
</welcome-file>
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 16 of 40
</welcome-file-list>
</web-app>
Now your Web application has a reference to the DataSource object.You can look
it up using the res-ref-name in the resource-ref in the web.xml file.Now
you're ready to use your DataSource in your service.
Section 3.Modify the StocksService interface
To modify your service,you need to first modify the interfaces used by clients.These
interfaces are compiled into JavaScript,but they also define the contract for your
server-side implementation of the service.In this section,you first modify the service
and then modify the application to make use of the new features in your service.
StocksService interfaces
You're ready to add portfolios to your application.Start by redefining your service
interface.Add two new methods to it,as shown in Listing 4.
Listing 4.StocksService interface
package org.developerworks.stocks.client;
import com.google.gwt.user.client.rpc.RemoteService;
public interface StocksService extends RemoteService {
public Stock getQuote(String symbol);
public Stock[] getPortfolio(String username);
public Stock[] addStocks(String username,String[]
symbols);
}
You've added two new methods:
• getPortfolio is for a user logging in.
• addStocks is used to save stocks to a portfolio.
Both return an array of stocks.You have to be careful about what you return.
Remember that the interface is used in JavaScript,so only a subset of Java classes
is allowed.You could use a java.util.List,java.util.ArrayList,or
java.util.Vector.However,you could not use generics as you might be
tempted to do — for example,you could not have a List<Stock> as a return type.
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 17 of 40
The JavaScript compiler only supports JDK 1.4 and later features.Because you
modified the interface,you also need to modify the asynchronous version of the
interface,as shown in Listing 5.
Listing 5.Asynchronous StocksService interface
package org.developerworks.stocks.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface StocksServiceAsync {
public void getQuote(String symbol,AsyncCallback
callback);
public void getPortfolio(String username,AsyncCallback
callback);
public void addStocks(String username,String[] symbols,
AsyncCallback callback);
}
You've followed the same pattern you used in Part 1.For each method defined in
your interface,you've added a method with the same name to your asynchronous
interface.The asynchronous versions all return void and all take one extra
parameter,an AsyncCallback object.This object is what stores the return value
from the service call.Now that you've updated your interfaces,you need to update
your implementation.
StocksService implementation
Add the two new methods defined in the StocksService interface to your
implementation class,as shown in Listing 6.
Listing 6.StocksService implementation
package org.developerworks.stocks.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.developerworks.stocks.client.Stock;
import org.developerworks.stocks.client.StocksService;
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 18 of 40
import com.google.gwt.user.client.rpc.InvocationException;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
public class StocksServiceImpl extends RemoteServiceServlet
implements StocksService {
private static final String YAHOO_QUOTE_URL =
"http://quote.yahoo.com/d/quotes.
csv?s=:symbol&f=sl1d1t1c1ohgvj1pp2owern&e=.csv";
private static final String LOOKUP ="select user_id from
user where name=?";
private static final String QUERY =
"select p.symbol from portfolio p,user u where
p.user_id =
u.user_id and u.name=?";
private static final String INSERT_STOCKS ="insert into
portfolio values (?,?)";
private static final String INSERT_USER ="insert into
user (name) values (?)";
public Stock getQuote(String symbol) {
String urlStr = YAHOO_QUOTE_URL.replace(":symbol",
symbol);
try {
URL url = new URL(urlStr);
URLConnection conn = url.openConnection();
conn.connect();
InputStream is = conn.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
Stock stock =new Stock();
while ( (line = br.readLine())!= null){
String[] stockArray = line.split(",");
for (int i=0;i<stockArray.length;i++){
stock.setCompanyName(stockArray[16].replaceAll("\"",""));
stock.setSymbol(stockArray[0].replaceAll("\"",""));
stock.setPrice(new Double(stockArray[1]));
stock.setChange(new
Double(stockArray[4]));
}
}
return stock;
} catch (MalformedURLException e) {
throw new InvocationException("Something was
wrong with the URL",e);
} catch (IOException e) {
throw new InvocationException("Exception reading
data from Yahoo",e);
}
}
public Stock[] addStocks(String username,String[]
symbols) {
DataSource ds = getDataSource();
try {
Connection conn = ds.getConnection();
PreparedStatement ps =
conn.prepareStatement(LOOKUP);
ps.setString(1,username);
ResultSet rs = ps.executeQuery();
Integer userId = null;
if (rs.next()){
userId = rs.getInt(1);
} else {
ps = conn.prepareStatement(INSERT_USER);
ps.setString(1,username);
int num = ps.executeUpdate();
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 19 of 40
if (num > 0){
rs = ps.getGeneratedKeys();
if (rs.next()){
userId = rs.getInt(1);
}
}
}
if (userId!= null){
ps = conn.prepareStatement(INSERT_STOCKS);
for (String symbol:symbols){
ps.setInt(1,userId);
ps.setString(2,symbol);
ps.addBatch();
}
ps.executeBatch();
conn.commit();
}
conn.close();
} catch (SQLException e) {
throw new InvocationException("Exception saving
stocks",e);
}
return this.getPortfolio(username);
}
public Stock[] getPortfolio(String username) {
DataSource ds = getDataSource();
try {
Connection conn = ds.getConnection();
PreparedStatement ps =
conn.prepareStatement(QUERY);
ps.setString(1,username);
ResultSet results = ps.executeQuery();
List<String> symbols = new LinkedList<String>();
while (results.next()){
symbols.add(results.getString(1));
}
//If this was"production"code,this would be
in a finally block,etc.
conn.close();
Stock[] stocks = new Stock[symbols.size()];
int cnt = 0;
for (String symbol:symbols){
stocks[cnt++] = this.getQuote(symbol);
}
return stocks;
} catch (SQLException e){
throw new InvocationException("Exeption querying
database",e);
}
}
private static DataSource getDataSource(){
InitialContext ctx;
try {
ctx = new InitialContext();
return (DataSource)
ctx.lookup("java:comp/env/jdbc/MyDataSource");
} catch (NamingException e) {
throw new InvocationException("Exception getting
datasoure",e);
}
}
}
Each of your two new methods makes heavy use of JDBC.To get a JDBC
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 20 of 40
connection,they call the static getDataSource() method.This method should
look pretty familiar.You simply look up your DataSource in JNDI.You use the
lookup string you got from the database connection pool usage shown in Figure 11.
Your getPortfolio method looks up all the stocks in a user's portfolio by
performing a join-query against the database.The query retrieves the stock symbol,
and you then reuse the getQuote method to get the metadata about the given
stock.
The addStocks method handles a couple of scenarios.First it handles the scenario
of a user adding a stock to his or her portfolio.It also handles a user who has added
multiple stocks and then saves them by inputting a user name.Finally,it handles a
user logging in after adding some stocks to a new portfolio.After persisting data,it
calls the getPortfolio() to requery the stocks.This lets you handle the last
scenario described,where a user has a portfolio but adds more stocks before
logging in.
Now that you've modified the service,you just need to modify the application to
make use of the new features in your service.
Modify the stocks application
Your back-end service has leveraged Geronimo to give you new portfolio features.
Now you need to modify your application code.The new code is shown in Listing 7.
Listing 7.StocksApplication
package org.developerworks.stocks.client;
import java.util.ArrayList;
import java.util.List;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.KeyboardListenerAdapter;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
/**
* Entry point classes define onModuleLoad().
*/
public class StocksApplication implements EntryPoint {
StocksService service;
/**
* This is the entry point method.
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 21 of 40
*/
public void onModuleLoad() {
final Button button = new Button("Get Quote");
final TextBox textBox = new TextBox();
final FlexTable stockTable = new FlexTable();
final Button userButton = new Button("Login");
final TextBox userBox = new TextBox();
final List symbolsList = new ArrayList();
final Label welcomeLabel = new Label();
final StocksServiceAsync stocksService =
(StocksServiceAsync)
GWT.create(StocksService.class);
ServiceDefTarget endpoint = (ServiceDefTarget)
stocksService;
String moduleRelativeURL = GWT.getModuleBaseURL() +
"stocksService";
endpoint.setServiceEntryPoint(moduleRelativeURL);
final AsyncCallback callback = new AsyncCallback() {
public void onFailure(Throwable caught) {
alert("Sorry there was an error");
}
public void onSuccess(Object result) {
Stock stock = (Stock) result;
int cnt = stockTable.getRowCount();
stockTable.setText(cnt,0,stock.toString());
//show things as green or red depending on if
the stock is up or down
if (stock.getChange() > 0){
stockTable.getCellFormatter().addStyleName(cnt,0,"stockUp");
} else if (stock.getChange() < 0){
stockTable.getCellFormatter().addStyleName(cnt,0,
"stockDown");
}
symbolsList.add(stock.getSymbol());
textBox.setText("");
}
};
final AsyncCallback userCallback = new AsyncCallback(){
public void onFailure(Throwable caught) {
alert("Sorry there was an error:"+
caught.getMessage());
}
public void onSuccess(Object result) {
Stock[] stocks = (Stock[]) result;
int cnt = stockTable.getRowCount();
//don't be tempted to use the new for loop --
//GWT does not support Java 5 in client code!
for (int i=0;i<stocks.length;i++){
if
(!symbolsList.contains(stocks[i].getSymbol())){
Stock stock = stocks[i];
stockTable.setText(cnt,0,
stock.toString());
if (stock.getChange() > 0){
stockTable.getCellFormatter().
addStyleName(cnt,0,
"stockUp");
} else if (stock.getChange() < 0){
stockTable.getCellFormatter().
addStyleName(cnt,0,
"stockDown");
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 22 of 40
}
cnt++;
symbolsList.add(stocks[i].getSymbol());
}
}
userButton.setVisible(false);
userBox.setVisible(false);
welcomeLabel.setText("Welcome
"+userBox.getText());
}
};
button.addClickListener(new ClickListener() {
public void onClick(Widget sender) {
String symbol = textBox.getText();
stocksService.getQuote(symbol,callback);
//check if logged in already
if (userBox.getText()!= null &&
userBox.getText().trim().
length() > 0){
stocksService.addStocks(userBox.getText(),new
String[]
{symbol},callback);
}
}
});
//make hitting Return the same as clicking the button
textBox.addKeyboardListener(new KeyboardListenerAdapter() {
public void onKeyPress(Widget sender,char keyCode,
int modifiers){
if (keyCode =='\r'){
button.click();
}
}
}
);
userButton.addClickListener(new ClickListener(){
public void onClick(Widget sender) {
String username = userBox.getText();
int cnt = stockTable.getRowCount();
if (cnt == 0){
//empty so login
stocksService.getPortfolio(username,
userCallback);
} else {
//not empty add user and save stocks
String[] symbols = new String[cnt];
for (int i=0;i<cnt;i++){
symbols[i] = (String)
symbolsList.get(i);
}
stocksService.addStocks(username,symbols,
userCallback);
}
}
});
//make hitting Return the same as clicking the button
userBox.addKeyboardListener(new KeyboardListenerAdapter() {
public void onKeyPress(Widget sender,char keyCode,
int modifiers){
if (keyCode =='\r'){
userButton.click();
}
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 23 of 40
}
}
);
//These are the elements that the widgets are being added
to
RootPanel.get("quoteButton").add(button);
RootPanel.get("quoteBox").add(textBox);
RootPanel.get("stockTable").add(stockTable);
RootPanel.get("userBox").add(userBox);
RootPanel.get("userButton").add(userButton);
RootPanel.get("welcome").add(welcomeLabel);
stockTable.setStyleName("center");
}
public static native void alert(String msg)/*-{
$wnd.alert(msg);
}-*/;
}
There are a lot of new things you've added,including:
• Allowing multiple stocks to have their information displayed on a page by
using a FlexTable instead of a Label.The FlexTable becomes an
HTML table but gives you an easy way to add rows and columns to a
table.
• A text box and a button for logging in.
• A label for displaying a welcome message to your user.
• A temporary data structure (a list) for keeping track of what stocks have
been added.This lets you save a list of stocks at any point.Notice that
you used a java.util.List and a java.util.ArrayList,because
these can be converted to JavaScript by GWT.
Handling events
Now that you've added the objects you need,you can call the new features on your
service by handling events.Your original button has had its handler modified.If your
user is logged in,then you make a second asynchronous call to persist the stock
information to the user's portfolio.Because of the asynchronous nature,you don't
have to wait for this before showing the stock info the user has just entered.The
persisting of the data happens without the user having to wait for it.That's a really
nice feature that's made easy to accomplish using GWT.
You added a handler for clicking the Login button.This checks to see if the user has
already added stocks or not.It makes a different call depending on whether it needs
to save the stocks to the user's portfolio.You also mapped the action of hitting the
Return button in the user box to clicking the button,just like you did for the quote
button.
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 24 of 40
Next you modified the existing callback to add the stocks to your data structure.The
new callback handles displaying the portfolio that's been retrieved.If there are
already stocks displayed,the callback just adds the new ones retrieved from the
server to the table.If the login was successful,the login box and button are hidden,
and a welcome message is displayed.
Finally,notice the error-handling process.You're using the static method alert().
Take a look at the implementation of this method — using GWT's JavaScript Native
Interface (JSNI).You declare the method as native (a reserved word in Java
technology usually denoting a call to C/C++ code) and then put your JavaScript
inside a comment.If you've ever done any JavaScript programming,you'll recognize
this as simple code for displaying a message in a pop-up box.You might be
wondering about the $wnd.This refers to the window object from the GWT
documentation (see Resources for a link),quoted below:
When accessing the browser's window and document objects from
JSNI,you must reference them as $wnd and $doc,respectively.
Your compiled script runs in a nested frame,and $wnd and $doc
are automatically initialized to correctly refer to the host page's
window and document.
This code is all compiled into JavaScript used by your Web page.You just need to
modify your Web page now,as shown in Listing 8.
Listing 8.StocksApplication.html
<html>
<head>
<title>GWT Stocks Application</title>
<style>
#stockInfo{
text-align:center;
padding-top:10px;
}
#quotes{
text-align:center;
}
#quoteBox{
padding-right:5px;
}
.stockUp{
color:green;
}
.stockDown{
color:red;
}
table.center {
margin-left:auto;
margin-right:auto;
}
body {
text-align:center;
}
h1,p {
text-align:left;
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 25 of 40
}
#welcome {
text-align:left;
font-size:large;
}
</style>
<!-- -->
<!-- The module reference below is the link -->
<!-- between html and your Web Toolkit module -->
<!-- -->
<meta name='gwt:module'
content='org.developerworks.stocks.
StocksApplication'>
</head>
<body>
<!-- -->
<!-- This script is required bootstrap stuff.-->
<!-- You can put it in the HEAD,but startup -->
<!-- is slightly faster if you include it here.-->
<!-- -->
<script language="javascript"src="gwt.js"></script>
<!-- OPTIONAL:include this if you want history
support -->
<iframe id="__gwt_historyFrame"
style="width:0;height:0;border:0"></iframe>
<h1>Stocks Application</h1>
<p>
<span id="welcome"/>
Enter in the symbol for a stock below.
</p>
<div id="quotes">
<span id="quoteBox"></span>
<span id="quoteButton"></span>
</div>
<div id="stockTable"/>
<div id="userInfo">
<span id="userBox"></span>
<span id="userButton"></span>
</div>
</body>
</html>
Not too many changes here.You've added some divs and spans to contain your
new UI components.You've also added some CSS for these objects.Now you're
ready to deploy your application to Geronimo.
Section 4.Deploy to Geronimo
In this section,you first build a new WAR file using Ant and then deploy it to
Geronimo before testing it.
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 26 of 40
Build a WAR file
To deploy your application,you need to build a new WAR file.You created an Ant
file for building the WAR file,which will still work perfectly for your modified
application.Invoke the WAR target on the build file,and you should see output
similar to Listing 9.
You might notice the compiler warning.This is caused by using the nongeneric
version of java.util.List in the StocksApplication.Of course,you couldn't
use the generic version of List,because this is code that's being compiled into
JavaScript,and GWT doesn't support generics (or any other Java 5 feature) in client
code.
Listing 9.Building the WAR file
Buildfile:C:\code\projects\stocks\build.xml
build:
[mkdir] Created dir:C:\code\projects\stocks\bin
[javac] Compiling 5 source files to C:\code\projects\stocks\bin
[javac] Note:C:\code\projects\stocks\src\org\developerworks\stocks
\client\StocksApplication.java uses unchecked or unsafe operations.
[javac] Note:Recompile with -Xlint:unchecked for details.
jar:
[mkdir] Created dir:C:\code\projects\stocks\www\StocksApplication
\WEB-INF\lib
[jar] Building jar:C:\code\projects\stocks\www\StocksApplication
\WEB-INF\lib\stocks.jar
gwt:
[exec] Output will be written into
C:\code\projects\stocks\www\org.developerworks.stocks.StocksApplication
[exec] Copying all files found on public path
[exec] Compilation succeeded
[copy] Copying 17 files to C:\code\projects\stocks\www\StocksApplication
war:
[copy] Copying 1 file to C:\code\projects\stocks\www\StocksApplication\WEB-INF\lib
[jar] Building jar:C:\code\projects\stocks\stocks.war
BUILD SUCCESSFUL
Total time:5 seconds
Your WAR file is now built,so you just need to deploy it to Geronimo.
Let's go back to the Geronimo Console:
1.This time select Applications > Deploy New,as shown in Figure 12.
Figure 12.Deploy new application
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 27 of 40
This brings up the install new applications interface.
2.Navigate to your WAR file and select it.If the old version of the
application is deployed,select the Redeploy application check box,as
shown in Figure 13.
Figure 13.New Application to Deploy
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 28 of 40
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 29 of 40
3.After clicking Install,the WAR file is deployed,and you should get a
message that it was successful.
4.Click Applications > Wab App WARs to verify that the application is
deployed,as shown in Figure 14.
Figure 14.Application successfully deployed
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 30 of 40
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 31 of 40
You should see your application in the list of Web applications,as seen in
Figure 15.
Figure 15.Web applications
Now your application is installed!You can begin testing it.
Test the application
1.Click the URL link for the Web application to bring it up,as shown in
Figure 16.
Figure 16.The portfolio application
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 32 of 40
2.Add some stocks,say IBM,CSCO,and SUNW,as shown in Figure 17.
Figure 17.Stocks added
3.Now save them.Type developerworks in the Login field,as shown in
Figure 18.
Figure 18.Logging in
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 33 of 40
4.Click the Login button,which should result in something similar to Figure
19.
Figure 19.Logged in
5.Now you can add some more stocks,which will be saved asynchronously.
Add GOOG,as shown in Figure 20.
Figure 20.Stock saved asynchronously
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 34 of 40
6.To verify everything was saved,simply reload the page.You never used
any session,and you kept track of all state on the client,so reloading
essentially logs you out.Type developerworks,and log in again,as
shown in Figure 21.
Figure 21.Logging back in
You should see a screen identical to Figure 20.Feel free to add some
more stocks,users,and so on.
Section 5.Summary
You've used Geronimo to add persistence to your Ajax-enabled Web application.
Now you have a portfolio management application.GWT and Geronimo made it
easy to rapidly build a modern Web application.From here you can continue to add
more GWT features or use more of Geronimo's features.Both GWT and Geronimo
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 35 of 40
have a lot to offer in increasing the functionality of your application.
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 36 of 40
Downloads
Description
Name
Size
Download
method
Part 2 source code stocks2.zip 10KB HTTP
Information about download methods
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 37 of 40
Resources
Learn
• The best place for GWT information is straight from the source,at the official
Google Web Toolkit site.
• Read one of the first in-depth tutorials on GWT in"Ajax for Java developers:
Exploring the Google Web Toolkit"(developerWorks,June 2006).
• Enjoyed building an Ajax-enabled Web application with GWT?Try out the
four-part tutorial series"Build an Ajax application using Google Web Toolkit,
Apache Derby,and Eclipse"(developerWorks,December 2006).
• Learn about using MySQL to build Enterprise Java™applications in"Designing
a Web service using Data Access Objects to access data in a DB2 or MySQL
database"(developerWorks,July 2006).
• Get an introduction to building Ajax applications using Java technology in the
article"Ajax for Java developers:Build dynamic Java applications"
(developerWorks,September 2005).
• Are you a fan of design patterns?Learn about some of the most useful Ajax
design patterns in the article"Ajax and XML:Five common Ajax patterns"
(developerWorks,March 2007).
• Learn about advanced GWT techniques in the online book Google Web Toolkit
Solutions:Cool & Useful Stuff.
• GWT is a great way to build an Ajax application with Geronimo,but it's certainly
not the only way.Build an Ajax application with JavaServer Faces and
Tomahawk in the tutorial"Build Apache Geronimo applications using
JavaServer Faces,Part 3:Add Ajax functionality with Ajax4jsf"
(developerWorks,October 2006).
• The developerWorks Apache Geronimo project resources has many useful
articles and tutorials on Geronimo.It even has an RSS feed!.
• Read the developerWorks article"Deploy J2EE applications on Apache
Geronimo"(developerWorks,January 2006).
• IBM Support for Apache Geronimo is an offering from IBM that provides
world-class support.
• Join the Apache Geronimo mailing list.
• Read Aaron Mulder's online book,Apache Geronimo Development and
Deployment,about installing and configuring the Apache Geronimo application
server titled.
• See the Geronimo Wiki for additional Geronimo documentation.
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 38 of 40
• Find helpful resources for beginners and experienced users at the Get started
now with Apache Geronimo section of developerWorks.
• Visit the developerWorks Open source zone for extensive how-to information,
tools,and project updates to help you develop with open source technologies
and use them with IBM's products.
• Stay current with developerWorks technical events and webcasts.
• Browse all the Apache articles and free Apache tutorials available in the
developerWorks Open source zone.
• Browse for books on these and other technical topics at the Safari bookstore.
• Get an RSS feed for this series.(Find out more about RSS.)
Get products and technologies
• GWT is not the only exciting new open source Java project from Google.Check
out Google Guice,a high-performance dependency injection framework.
• Download the latest version of Apache Geronimo.
• Download your free copy of IBM WebSphere® Application Server Community
Edition -- a lightweight J2EE application server built on Apache Geronimo open
source technology that is designed to help you accelerate your development
and deployment efforts.
Discuss
• Participate in the discussion forum for this content.
• Learn about and discuss the latest GWT news and its roadmap at the official
GWT blog.
• Discuss the GWT roadmap at the GWT Wiki.
• GWT may come from Google,but it's completely open source.You can
participate in making GWT better.
About the author
Michael Galpin
Michael Galpin has been developing Java software professionally since
1998.He holds a degree in mathematics from the California Institute of
Technology and currently works at Adomo,Inc.
ibm.com/developerWorks developerWorks®
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 39 of 40
Trademarks
IBM,the IBM logo,and WebSphere are registered trademarks of IBM in the United
States,other countries or both.
Java and all Java-based trademarks are trademarks of Sun Microsystems,Inc.,in the
United States,other countries,or both.
developerWorks® ibm.com/developerWorks
Integrate your Ajax apps with a back-end MySQL database using a servlet Trademarks
©Copyright IBM Corporation 2007.All rights reserved.Page 40 of 40