JavaEnterprise JavaDeveloping Ajax Web Applications using ThinWire and Java

Developing Ajax Web Applications using ThinWire and Java

Java Programming Notes # 2500


Preface

This is the first in a series of lessons designed to teach you how to
develop rich web applications using ThinWire and Java.

What in the world is ThinWire?

I gave you a brief introduction to ThinWire in my earlier lesson entitled
Deployment of Web Applications
in Jakarta Apache Tomcat 5
.  In this, and subsequent lessons, I will teach
you a great deal more about ThinWire.

Here is a quotation from the
ThinWire
web site that helps to explain what
ThinWire
is.

"ThinWire™ is a development framework that allows you to easily build
applications for the web that look and feel like the desktop applications
you’re familiar with."

Partial list of interesting features

Here is an edited list of interesting features that I extracted from the
ThinWire website.  (Note that I used boldface to highlight some features that I find
particularly interesting.)

  • Development framework for architecting Rich Internet Applications (RIA)
    that utilize Ajax techniques
  • Familiar event-driven GUI programming model
  • Develop exclusively in server-side language only

    • Never use HTML, CSS, or JavaScript again!
    • Program exclusively in Java!
    • Server-Side execution of all application logic

  • Rich Set of Complex Widget Components

    • Menu with image & shortcut-key support
    • Grid with multiple sortable columns
    • TextField & DropDown with real-time edit masking
    • Editable DropDown with multiple sortable columns
    • Tree control with image support
    • TabFolder with image support
    • Push buttons with images!

  • Content is sent incrementally and only when needed
  • All Major Browsers Supported
  • Deploy on any Java Servlet Container

What does this author think of the ThinWire
framework?

For those who know how to write stand-alone, event-driven Java/OOP
applications, this is the easiest way that I know of to
develop rich web applications.

Why will I be hedging?

From time to time in this series of lessons, you may detect that I am
unwilling to make a definitive statement about some ThinWire
topic.  I will sometimes use phrases line "I think" and "I
believe
that something or another is true.

My unwillingness to make a definitive statement about this or that will
derive from the fact that many of the details regarding the ThinWire
API have not yet been published.  Much of what I will be telling you in
this series of tutorials is based on what I have learned through
experimentation.

ThinWire is very new

What I believe was the first announcement of the release of the technology
appeared on the CCS website
with a date of June 15, 2006.  That announcement read as follows:

"6.15.2006  CCS
announces the open source release of its new
ThinWire(TM) technology
.

This advanced new technology platform enables highly secure solutions
within a zero footprint environment. The technology is now available for
general use within any web based application under open source terms."

Somehow I stumbled onto that announcement, and was immediately impressed with
the capabilities and the potential of the ThinWire
framework.  However, that was less than two months before the date on which
I am writing this first tutorial lesson in the series, and there are some things
that I am still unsure of.

An adventure into a new technology

If you join me in this ThinWire
adventure, we will be plowing new ground until such time as the ThinWire
documentation catches up with the ThinWire
capability.

Normally, I wouldn’t get involved with a new product at such an early stage
in its development.  Given that, my willingness to become deeply involved
in the ThinWire
framework technology is an indication of my extremely favorable impression of
its capabilities.

Written exclusively in Java

As mentioned above, with ThinWire, all of the code
for a web application is written exclusively in Java. 
You don’t have to contend with JavaScript or HTML.  Furthermore, you don’t
even have to contend with the complexity of Java servlets.  The code is
written like an event-driven standalone desktop application.  All of the complexity of
converting the application so that it will run as a server-side servlet-based
web application is handled by the ThinWire
framework.

Deploy on any Java Servlet Container

The last item in the
above list of features is a double-edged sword. 
JavaHeads like me would argue that this is clearly a useful feature because
it means that web applications developed using ThinWire can be deployed on a
variety of competing servers from different vendors.

Critics, on the other hand, would probably turn the statement around and
complain that a web application developed using ThinWire can only
be deployed on servers that support Java servlets.  Clearly, this is a
question of whether the glass is half full or half empty.

So, what is the ThinWire framework?

At the minimum, the ThinWire framework consists of the set of three
JAR files shown in Figure 1, plus a set of javadocs and a template of a file named
web.xml
:

 22,379 commons-fileupload.jar
  5,521 retroweaver-rt.jar
313,731 thinwire.jar
Figure 1

(The list of JAR files in Figure 1 shows the size of each file in bytes in
addition to the names of the Jar files.  You must copy these JAR files onto your computer
and adjust your classpath at compile time so that they are at the beginning
of the classpath.  I will explain how I do this later.)

No install operation required

No complex install operation is required for the ThinWire
framework.  You simply download a
zip file that contains the following items:

  • A LICENSE.TXT file and a ReadMe.txt file,
  • The jar files listed in Figure 1,
  • The javadocs,
  • A template for a web.xml file required for deployment in the
    servlet container.
  • Some demo programs, and
  • A scaled-down Tomcat server.

(As of the date of this writing, ThinWire version 1.2 beta is available
for free downloading.  I expect that by the time this tutorial makes its
way through the publication queue and into publication, a later version will
have been released.)

Just extract the pieces that you need

For installation, you simply open the zip file and extract the pieces that
you need.  As a minimum, you will need the set of jar files, the web.xml
file template, and the javadocs.  (Of course, you will want to read the license
file
and the ReadMe file.)

A servlet container is required for application
testing

If you already have access to a servlet container such as Tomcat, you won’t
need the scaled-down Tomcat server, so you won’t even need to extract it from
the zip file.  If not, you can extract and use the scaled-down Tomcat
server for application development and testing until you gain access to a
full-featured servlet container.

(You can download a full Jakarta Tomcat server for free from a variety
of locations on the web, including a pre-configured version from
Marty Hall’s web site.  See
my earlier lesson entitled
Getting Started with
Jakarta Tomcat, Servlets, and JSP
.)

Viewing tip

You may find it useful to open another copy of this lesson in a
separate browser window.  That will make it easier for you to
scroll back
and forth among the different listings and figures while you are
reading
about them.

Supplementary material

I recommend that you also study the other lessons in my extensive
collection of online Java tutorials.  You will find those lessons
published
at Gamelan.com
However, as of the date of this writing, Gamelan doesn’t maintain a
consolidated index of my Java tutorial lessons, and sometimes they are
difficult to locate there.  You will find a consolidated index at www.DickBaldwin.com.

Building the Web
Application

I suspect that the burning question on everyone’s mind is:

"How do I use the ThinWire
framework along with a Java source code file to build a web
application?"

So, I’m going to give you the bottom line at the beginning.

(I wasted quite a lot of time at the beginning searching the
ThinWire framework looking for something like a
"build file" that could be used to build the web application.  When I
finally discovered how it is done, I experienced one of those WOW! moments.)

The bottom line

Once you have a correctly written Java application all that is necessary to
build the web application is to:

Compile your Java application using Sun’s javac compiler with the
three ThinWire JAR files at the
beginning of the classpath.

That’s all there is to it.  It’s that simple.  (I will explain
later how I handle the classpath issue.)

If the compilation
is successful, it will produce all the class files you need to deploy your
web application in
a servlet container.  All you will need
is those class files and a very simple web.xml file that I will also explain
later (see Listing 1).

What is a correctly written Java application?

A correctly written Java application in the
context of ThinWire is one that was written taking the
ThinWire programming API into account.  In particular, this means that in
those cases where the ThinWire API contains classes, interfaces, and methods
with names that duplicate the names of classes, interfaces, and methods in the
standard Java library, you must write your code to be consistent with the
ThinWire API.

For example, both the ThinWire API and
Sun’s J2SE 5.0 API contain a
class named Button.  However, the Button class in the
ThinWire API provides a feature that is
not available with the Button class in the J2SE 5.0 API.  In
particular, you can put an image on a ThinWire
Button, but you can’t put an image on a J2SE 5.0 Button.

To implement this added feature, there is an overloaded Button constructor
in the ThinWire API that allows you to pass the name of
an image file as a parameter to the constructor.  This causes the image
to appear on the button, something that isn’t possible with a standard Sun
Button
.

Dealing with the classpath

The easiest way that I have found to deal with the classpath issue mentioned
above is to use the -cp switch of Sun’s javac compiler.  The easiest
and most reliable way to do that is to execute a
batch file containing the statement needed to compile my Java application. 
For example, here is the statement that I would use in the batch file to compile
the Java source code for the web application named WebApp003.

javac -cp 
C:...webappsWebApp003WEB-INFlibthinwire.jar;
C:...webappsWebApp003WEB-INFlib
retroweaver-rt.jar;
C:...webappsWebApp003WEB-INFlib
commons-fileupload.jar 
WebApp003.java

The ellipses (…) indicate the path from the root of my C drive to my
webapps development directory.

Must be a single-line command

Keep in mind that even though I
entered line breaks for display purposes in the version of the command shown
above, this is a single command so it
would appear on a single line if the display space would accommodate such a long
line.  When you use your text editor to create your batch file, you must
put it all on a single line.

Location of the batch file

My batch file is named compile.bat and it is located in the same
directory as the Java source file being compiled.  (See Figure 5.)  Then I simply
double-click on the batch file to perform the compilation.

It will be useful for you to compare this command with the directory
structure shown in Figure 5 to see how it fits into the overall directory
structure.

Preview

In this lesson, I will present and explain the Java source code for four
different sample web applications that I have developed using ThinWire.  The
following list identifies the main features illustrated by each application. 
The detailed explanation of the source code that I will provide later will identify other features.

  • WebApp003 – Illustrates PropertyChangeEvent handling on a
    Frame object.  Also illustrates the use of a TextArea object in the user interface.
  • WebApp004 – Illustrates PropertyChangeEvent handling on a
    TextArea object and ActionEvent handling on a Button.
  • WebApp006 – Illustrates the ability to use the power of
    server-side Java servlets to provide a computational service to a web client as a
    web application.  Also illustrates control over the style of GUI
    components and images on buttons.
  • WebApp008 – Same as WebApp006 but uses a better
    programming style.

Before getting into the detailed discussion of the applications, I will show
and explain screen shots of the user interface for each application as rendered in an Internet Explorer web browser.

WebApp003

The user interface for this web application is shown in Figure 2.


Figure 2

As mentioned earlier, this application illustrates PropertyChangeEvent handling on a
Frame object.  In addition, the application illustrates the use
of a TextArea object in the user interface.

Instantiating a Frame object

As you will see later when I explain the Java code, the instantiation of a
Frame
object in ThinWire differs from the way that a Frame object is
instantiated in J2SE 5.0.  Further, the visual manifestation of the
Frame
object is also different in ThinWire.

Visual manifestation of the Frame object

A Frame object that is instantiated using J2SE 5.0 is a top-level
container with decorations that can be placed directly on the computer desktop.

A Frame object instantiated under ThinWire
takes over the browser window in the browser being used to communicate with the
web application.

The entire browser window (not just the client area of the browser) is
contained in the Frame object. 
The title of the Frame object becomes the browser’s title as shown at the
top of the image in Figure 2.  When rendered in a Firefox tabbed browser,
the title becomes the
title for the tab.

What happens when you manually resize the browser?

Because the entire browser window is contained in the Frame object.,
manually resizing the browser also resizes the Frame object.

The behavior of the application

The primary behavior of the application named WebApp003 is to listen
for PropertyChangeEvents on the Frame object, with special
emphasis on the width and height properties.  When a
PropertyChangeEvent
attributed to one of those two properties is fired by
the Frame, the
program gets and displays the new size of the Frame object in a
TextArea
object.

Changing the size of the browser

When the size of the browser changes, the width property and/or the
height property of the Frame object will also change, causing a
PropertyChangeEvent
to be fired.  The event handler gets the new width
and height of the Frame object and concatenates that new information onto
the text that was already in the TextArea object with a line break
separating the new material from the old material.

The TextArea object

The TextArea object is shown in gray in Figure 2.  It is used for
display purposes only in this application.  Therefore, it is disabled to
prevent the user from being able to enter text into it.

When the text area becomes full, vertical scroll bars automatically appear on
the text area.

Only 22 lines of Java source code required

As you will see later, the entire Java program required to produce this web application
consisted of only 22 lines of Java source code.  This included about five
or six lines that contained nothing but curly braces.

WebApp004

The user interface, as rendered in an Internet Explorer browser, is shown in
Figure 3.


Figure 3

Action and PropertyChange event handlers

This application illustrates ActionEvent handling on a Button object
and PropertyChangeEvent handling on a TextArea object.

Differences in listener registration methods

As you will see later, the addActionListener
and addPropertyChangeListener methods in ThinWire are different from
those in J2SE 5.0.  These two methods in ThinWire have an extra parameter. 
The extra parameter is a String object or an array of String
objects.

For the addActionListener
method, the String object identifies the actions that will be monitored
by the listener object.

For the addPropertyChangeListener method, the String object(s)
identify the properties that the listener will monitor in an attempt to
determine if the property values have changed.

One action, many properties

As of ThinWire version 1.2 beta, there is only one kind of action and it is
specified as ACTION_CLICK.  However, there are dozens of different
properties that apply in different combinations to different components. 
This program uses PROPERTY_WIDTH and PROPERTY_HEIGHT.

Components to be notified of events

The addActionListener
method registers a listener on the component that
will be the source of the event when the specified action occurs.

The addPropertyChangeListener method registers a listener on the component that will be
the source of the event
when the value of any of the specified properties changes.

Four Button objects and a TextArea object

As you can see in Figure 3, this program places four Button objects
and a disabled TextArea object in a Frame object that fills the entire
browser window.

Behavior of the program

Anonymous ActionEvent handlers are registered on each of the buttons. 
Two of the buttons increase and decrease the width of the text area when they
are clicked.  The other two buttons increase and decrease the height of the
text area when they are clicked.

An anonymous PropertyChangeListener is registered on the TextArea
object, listening for a change in either the width or the height of the text
area.  Clicking any one of the four buttons will change the width or the height of the text area,
causing a
PropertyChangeEvent
to be fired by the TextArea object.

The
PropertyChangeEvent
handler displays the new width and height of the
TextArea
object in the text area,
concatenating the new information onto the text that was already there, with a line break
separating the new material from the old material.

Scroll bars appear automatically

When the TextArea becomes full, a vertical scroll bar automatically
appears.

When the width of the text area is
decreased to less than the length of the longest line of text, a horizontal
scrollbar does not appear.  Rather, the text wraps to the next line, and appears to
wrap correctly at word boundaries.  However, when the width of the text area
becomes less than the length of the longest word, a horizontal scroll bar
does
appear
automatically.

WebApp006

The user interface for this web application, as rendered in Internet
Explorer, is shown in Figure 4.


Figure 4

The power of server-side Java

This web application illustrates the ability to use the power of server-side
Java to provide a computational service to a client as a web application. 
Although the computational example used in this application is not sophisticated, it should
serve to illustrate that if you can program a computational algorithm in Java, you
can serve it as a web application.

Component style and images on components

The application also illustrates how to change the style of GUI components,
and how to put images on buttons.

The computational service

This application provides information about the monthly balance in a
savings account instrument.  It assumes a monthly deposit of a fixed amount
into a savings instrument for a fixed number of months, at a fixed annual
percentage rate.  The following three parameters are provided as user input
via three TextField objects:

  • Monthly deposit amount
  • Annual percentage rate
  • Number of months

The user interface

As you can see in Figure 4, the application places
the three TextField
objects, a Button object, and a TextArea object in a Frame
(along with some Label objects for cosmetic purposes).  Note
that there is an image on the Button.

The behavior

Each time the user clicks the OK button, the application gets the
Monthly Deposit
amount, the Annual Percentage Rate, and the Number
of Months
from the client via the three TextField objects.

Then the application computes and displays a table in the TextArea
showing the month number and the balance at the end of each month. 
(Note that the TextArea object shown in Figure 4 is automatically displaying a
vertical scroll bar.)

Data entry errors

If the user enters something into one of the text fields that can’t be parsed
into a numeric value, and then clicks the OK button, the text area is
cleared and an error message appears in the leftmost TextField object.

Changing the style of a component

For illustration purposes, the style of the leftmost TextField object
was changed from the default to the following:

  • Background Color = RED
  • Text = Bold
  • Border Color = BLACK
  • Border Type = DOUBLE

The remaining two TextField objects were displayed in their default
style, which is probably what you are more accustomed to seeing for a text
field.

Construction of the Button object with an image

The Button object was constructed by passing the name of an image file
to the constructor for the Button.  Note that this constructor for
the ThinWire Button class is different from and more sophisticated than
any of the Button constructors in the AWT.  An AWT button cannot
display an image (but a Swing JButton can).

Different from an AWT TextField object

The ability to change the style of a TextField object is also different from the capabilities offered by the AWT.  As I
recall, it is not possible to modify the default border for an AWT TextField
object.  (However, it is possible to modify the border for a Swing
JTextField
object.)

Somewhere between the AWT and Swing

Therefore, the available features of the ThinWire GUI component set seem to fall
somewhere between the AWT and Swing.  ThinWire GUI components are somewhat
richer than the corresponding AWT components, and probably less rich than the
corresponding Swing components.

For example, you can specify any one of nine different border styles for a
ThinWire Button, which is more than you can do with the AWT. 
(You can’t change the default border on an AWT button.)
  However, you
can change the border on a Swing JButton in an almost infinite variety of
ways.

You can also make a Swing JButton transparent, but I don’t believe
that you can make a ThinWire Button transparent.

Additional components

ThinWire version 1.2 beta provides about 25
different GUI components.  The component set includes the typical
components such as Button, Label, and TextField, which are available in the
standard Java AWT, plus some fancy components that don’t exist in the AWT:

  • Tree
  • TabFolder
  • WebBrowser

I will have more to say about GUI components in a future lesson that will
concentrate on the ThinWire GUI component set.

The Playground Demo interactive web application

To give you a brief idea of what’s coming down the pike, ThinWire will soon
release a sophisticated interactive Ajax web application currently being
referred as the "Playground Demo."  This interactive web
application, which will become an important programming tool and not just a
demo, is being developed using ThinWire technology.

Truly impressive!

As of the date of this writing, the Playground web application hasn’t been
released to the public, but I have been given access to a preview
version.  This web application is truly impressive in its current state,
and it is getting better all the time.

An important programming tool

In its current state, the Playground Demo lets you interact with each of about
eighteen
different ThinWire GUI components.  In operation, you can
interactively:

  • View the component on the screen as it would be rendered in your
    browser.
  • Change any of the properties and see the results of each change when you
    click a button to apply the modified properties.
  • Change any of the style parameters and see the results of each change
    when you apply the modified style parameters.
  • View the list of supported events.

And perhaps best of all, you can cause the Playground Demo to generate the
Java source code for the current component and settings you’ve selected by
clicking the “Source Code” tab.

WebApp008

The user interface for this web application, as rendered in Internet
Explorer, is the same as WebApp006 and therefore is also shown in Figure
4.

The behavior of this web application is identical to WebApp006
The purpose of this application is to illustrate the use of a different
programming style than was used in WebApp006.  I will explain the
differences later when I explain the code.

The web application directory structure

In my earlier lesson entitled
Deployment of Web Applications in Jakarta
Apache Tomcat 5
, I explained the general directory structure requirements for
deploying a web application in jakarta-tomcat-5.0.27.  The web applications
that I will explain in this lesson follow those general requirements.

The most complicated directory structure

The most complicated directory structure of the four web applications in this
lesson is the
structure required for WebApp008.  This directory structure is shown in
Figure 5 with directory names being highlighted in boldface and file names being
shown in ordinary text.

Dir: WebApp008
.Dir: images
..redball.gif
.Dir: WEB-INF
..Dir: classes
...Dir: pkgdemo
....GUI$1.class
....GUI.class
....WebApp008$1.class
....WebApp008.class
....compile.bat
....WebApp008.java
..Dir: lib
...commons-fileupload.jar
...retroweaver-rt.jar
...thinwire.jar
..web.xml
Figure 5

Compare with requirements in the earlier lesson

If you compare Figure 5 with the examples shown in the earlier lesson entitled
Deployment of Web Applications in Jakarta Apache Tomcat 5, you will see
that it compares very favorably with those examples.  The biggest
difference is that the Java source code in Figure 5 is stored along with the
class files in the directory named pkgdemo, whereas a special directory
named src was set aside for the storage of source code in the earlier
lesson.

(As a practical matter, there is no technical requirement to store
the source code on the server at all.  It is simply a convenient place to
store the source code along with the other files that constitute the web
application.)

The file named web.xml

You learned about the required file named web.xml in the earlier
lesson entitled Deployment of Web Applications in Jakarta Apache Tomcat 5.  I will explain the
Java source code for each application in the sections that
follow.  However, I will explain the code for the file named web.xml
only once, and this is it.

A general template for the web.xml file is shown in
Listing 1.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.
//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
  <display-name>ThinWire_SimpleAppDemo</display-name>
  <description>ThinWire Simple App Demo Application
  </description>

  <servlet>
    <servlet-name>thinwire</servlet-name>      
    <description>ThinWire Servlet Engine</description>
    <servlet-class>thinwire.render.web.WebServlet
    </servlet-class>
  
    <init-param>
      <param-name>mainClass</param-name>
      <param-value>Path.AppName</param-value>        
    </init-param>
  </servlet>
    
  <servlet-mapping>
    <servlet-name>thinwire</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>    
</web-app>


Listing 1

Replace content of param-value element

You will need to replace Path.AppName in Listing 1 by the path
(relative to the classes directory)
and file name of the class file
produced by compiling the Java source code that contains your main
method.  Otherwise, you can probably copy and use the code in Listing 1 for
most, if not all ThinWire web applications.

Optional replacements

In addition, you can optionally replace the content of the display-name
and description elements to make them more descriptive of your
application, but that is not a technical requirement.

Discussion
and Sample Code

I will provide a detailed discussion and explanation of each of the four web
applications described above in this section.

The Web Application Named WebApp003

Behavior of the Web Application

I described the general behavior of this web application
earlier
, so I won’t repeat that explanation here.

The Tomcat directory structure

The directory structure for this application is shown in Figure 6.

Dir: WebApp003
.ReadMe.htm
.Dir: WEB-INF
..Dir: classes
...Dir: pkgdemo
....compile.bat
....WebApp003$1.class
....WebApp003$2.class
....WebApp003.class
....WebApp003.java
..Dir: lib
...commons-fileupload.jar
...retroweaver-rt.jar
...thinwire.jar
..web.xml
Figure 6

Practical considerations

Because I deploy my web applications in jakarta-tomcat-5.0.27 for localhost
testing, my approach to developing web applications is to create a development tree
that has the same directory structure as that which will ultimately be required
by jakarta-tomcat-5.0.27.

I create my Java source code file, my web.xml file, my compilation
batch file, etc., in that directory tree.  For the development of web
applications using
ThinWire, I also place a copy of the
ThinWire JAR files in the lib directory of that tree as well.

Copy the completed web application

After I have successfully compiled the application, I simply copy the
entire directory tree, beginning with the application root directory (the
WebApp003
directory in this case)
into the webapps directory of
the jakarta-tomcat-5.0.27 tree structure.

Testing the web application

Having copied the completed web application into the jakarta-tomcat-5.0.27
tree structure, I start the server running and point my browser to the URL that defines the
application root directory for the application in the server.  For example, to test this
application, I would point my browser to the following URL:

http://localhost/WebApp003/

Be careful when copying

The jakarta-tomcat-5.0.27 tree structure is fairly large and complex. 
In order to avoid the possibility of copying my completed application into the
wrong location in that tree structure, and then having to repair the damage, I don’t copy
directly into the tree.  Rather, I have created a shortcut on my desktop that points to the webapps
directory in the jakarta-tomcat-5.0.27 tree structure.

When time comes to
do the copy, I copy the completed application onto the folder icon that visually
represents the shortcut on the desktop. 
That causes it to be copied into the webapps directory. 
If I happen to miss the mark, it is simply copied onto the desktop, which is a
much easier situation to repair.

Starting and stopping the server

The safest approach for testing is to stop the server following each test, perform the
copy, and then restart the server.  However, sometimes you can get by with doing the
copy without stopping the server first.  This won’t cause any lasting
problems, but sometimes your application won’t execute properly if you do this. 
In that case, just stop and restart the server and repeat the test.

Don’t let the server get bloated

Because the server software does some configuration work for each web
application on startup, the more web applications that exist in the webapps
directory, the longer it will take for the server to become ready for use on
startup.  Therefore, if you are testing a lot of web applications, it is a
good idea to stop the server and move those applications that are not currently
being used into an archive directory.  This will allow the
jakarta-tomcat-5.0.27 server to become ready for use more quickly when you start
it.

The web.xml file

The required web.xml file for this application matches that shown in
Listing 1 except that Path.AppName in Listing 1 is replaced by
pkgdemo.WebApp003
for this application.

The Java source code

A complete listing of the Java source code for this application is shown in
Listing 25 near the end of the lesson.  I will discuss and explain that
source code in fragments.  The first such fragment is presented in Listing
2.

The class definition and the main method for WebApp003 begin in Listing 2.

package pkgdemo;

import thinwire.ui.*;
import thinwire.ui.event.*;

public class WebApp003{
  public static void main(String[] args){

Listing 2

The package declaration

First note the package declaration in Listing 2.  This is what requires
that the class files for this application be stored in the directory named
pkgdemo
, shown as a child of the directory named classes in Figure 6.

All four of the web applications that I will explain in this lesson are
declared to be in the same package, so I won’t need to mention this again.

The import directives

The ThinWire API for version 1.2 beta is subdivided into the following five
packages:

  • thinwire.ui
  • thinwire.ui.event
  • thinwire.ui.layout
  • thinwire.ui.style
  • thinwire.util

As you can see from Listing 2, this application imports classes from the
first two packages in the list.  Classes in the first package are required in order
to use the GUI components Frame and TextArea.

Classes in the second package are required to support event handling for a
PropertyChangeListener
.  All four applications that I will explain in
this lesson will require the importing of classes from these two packages. 
In addition, one of the later applications will also require the importing of
classes from the thinwire.ui.style package.

The name of the class

A ThinWire web application can consist of many different classes. 
Although I’m not certain, I believe that the class that defines the main method must have the same name as the
name of the web application.  This is so that the compilation will produce
a class file with the same name as the web application.  In this case, the
name of the class is WebApp003, which is also the name of the web
application.

(It may be possible to use different names and to rectify the
differences in the web.xml file.  In any event, the applications
in this lesson follow the rules given
above.)

The main method

As I explained earlier, creating a web application using ThinWire is almost
exactly the same as creating a standalone Java application having a main
method.  The only real difference is that you must comply with the ThinWire
API for those classes, interfaces, and methods that duplicate the names of classes, interfaces,
and methods in the standard J2SE library.

The standard signature for the main method is shown as the last line
of code in the fragment in Listing 2.

Where is the executable code?

The first three applications that I will explain in this lesson have all of
the executable code placed in the main method.  Although I don’t consider
this to be a good programming style, I used it because it is easy to write and
easy to understand.

To illustrate that the use of this programming style is not a ThinWire
requirement, the fourth application, named WebApp008, is a rewrite of WebApp006
where most of the code was removed from the main method and placed in a
different class.

Get a Frame object

The code in Listing 3 instantiates a Frame object and sets its
title.

    final Frame frame = Application.current().getFrame();

    frame.setTitle("PropertyChangeEvent Test");

Listing 3

Note that the syntax for instantiating a Frame object in ThinWire is
considerably different from the syntax used to instantiate a Frame object in J2SE 5.0. 
Unlike a J2SE 5.0 Frame object, a ThinWire Frame object is not a
top-level container that can be independently placed on the desktop.  Instead, a ThinWire
Frame object essentially takes over the entire browser window.  It cannot be placed on the desktop outside of the real estate
occupied by the browser.  There are no public constructors for a ThinWire
Frame
object.

What do the ThinWire javadocs have to say?

According to the ThinWire javadocs, the code shown in Listing 3
"Gets the
Frame that represents the primary application window." 

I’m not going to try to explain this in any more depth, because I couldn’t even
if I wanted to.  Rather, I will simply refer you to the ThinWire javadocs
for additional information if you need it.

As a reminder, this is one of those cases where you must write your Java code
taking the ThinWire API into account.

The Frame title

Listing 3 uses a conventional setter method to establish the title for the
Frame
object.  In the case of the ThinWire web application, this title
becomes the browser’s title, and in the case of a Firefox tabbed browser, it
also becomes the title for the tab.

The TextArea object

The code in Listing 4:

  • Instantiates a new TextArea object.
  • Establishes where it will appear relative to the upper left corner of
    the Frame.
  • Establishes the size of the TextArea object in pixels.
  • Disables the TextArea object to prevent the user from entering data into it. 
    The TextArea object is used
    solely for display purposes in this application.
    final TextArea textArea = new TextArea(
                         "Frame Size is Displayed Heren");
    textArea.setBounds(0,0,200,200);
    textArea.setEnabled(false);

Listing 4

Identical to standalone application code

The code in Listing 4 is identical to code that you would write if you were
creating a stand-alone Java application for which the layout manager on the
Frame
has been set to null.

The reference to the TextArea object is declared to be final because it is a
local variable that will be referenced in an inner class.  This is a
general Java requirement and not a ThinWire requirement.

Add the TextArea to the Frame

Listing 5 causes the TextArea object to be added to the Frame
object.

This syntax is also different from what you find in J2SE 5.0, and
you will see a lot of it as you pursue the ThinWire
API.

    frame.getChildren().add(textArea);

Listing 5

In J2SE 5.0, you would simply invoke an add method on the Frame
object, passing the TextArea object’s reference as a parameter.

Interpretation of the code

The syntax in Listing 5 appears to get a reference to a data collection
object that contains a list of the objects belonging to the Frame, and to
invoke the add method on the collection, adding the TextArea to
the collection.  I suspect that this is
also what is done in J2SE 5.0, except that Sun has abstracted some of the details
away from the programmer.

This general approach will show up again later when dealing with component
properties.

The addPropertyChangeListener method

The listener registration methods in J2SE 5.0 typically require a single
parameter.  That parameter must be a reference to an object instantiated
from a specific listener interface, such as the PropertyChangeListener
interface.

The listener registration methods in ThinWire typically require two
parameters.  The second parameter is the same as the only parameter in J2SE
5.0, so I won’t belabor it.  The interesting parameter is the first
parameter in the ThinWire version.

Two overloaded versions

There are two overloaded versions of the addPropertyChangeListener
method for the Frame class in ThinWire.  One version requires a
reference to a String object as the first parameter.  The other
version requires a reference to an array object of type String as the
first parameter.

First consider the version that requires a parameter of type String
The ThinWire javadocs describe the contents of the String object as
"the name of the property that the listener will receive change events for."
 
In other words, given that a component has many properties that are subject to
change, if you want to monitor for changes in only one of those properties, this
is how you specify the property that you want to monitor.

(Note that this approach is considerably different from, and somewhat
simpler than the approach used in J2SE 5.0.  J2SE 5.0 uses a concept
known as bound properties to accomplish essentially the same thing. 
You can learn about bound properties in my earlier lesson entitled
JavaBeans, Properties
of Beans, Bound Properties
.)

How do you specify the property?

If you open the Index at the top of a javadocs page and then select any of the
items in the index that begin with PROPERTY_, that will expose a link
named Constant Field Values.  Select that link and you will see a
huge table, apparently containing all of the named constants defined in the ThinWire API.

(There is probably an easier way to access this table, but I haven’t
yet figured out what it is.)

This table includes dozens of properties which apply in different
combinations to different components.  The named constants for these
properties have names like PROPERTY_WIDTH and PROPERTY_HEIGHT
This table also provides the string values for these constants, such as
"width"
and "height", but it would probably be better programming
style to use the named constants rather than their absolute values.

Also, the applicable named constants for a particular component will be
given in the javadocs for that component.  Be aware, however, that they
will often be in the sections of the javadocs that identify the fields were
inherited from a superclass, because they are often defined in a superclass of
the component class.

A String array parameter

Now consider the other overloaded version of the addPropertyChangeListener that
requires a reference to an array object of type String as the first
parameter.  (That is the version used in this application.)  The
javadocs describe the contents of the String object referred to by the
references in the array object as "a string array of property names that the
listener will receive change events for."

In other words, if you want a given listener object to monitor for changes in
two or more different properties belonging to the component on which it is
registered, create an array object containing references to two or more
String
objects that identify those properties.  (Once again, it would
probably be better to use the named constants rather than the absolute values
of the strings.)
  Then pass that array object’s reference as the first
parameter to the registration method named addPropertyChangeListener.

Implementing this concept

That brings us to the code that implements this concept that begins in
Listing 6.

    String[] properties = {Frame.PROPERTY_WIDTH,
                           Frame.PROPERTY_HEIGHT};

Listing 6

Listing 6 creates and populates a two-element array object that will be used
to tell the registered PropertyChangeListener object to monitor for
changes in the values of the two properties shown, and to execute the method
named propertyChange when the value of either property belonging to the
Frame
object changes.

An anonymous inner class

The remaining implementation of this concept is shown in Listing 7.

    frame.addPropertyChangeListener(properties,
      new PropertyChangeListener(){
        public void propertyChange(PropertyChangeEvent e){
          textArea.setText(textArea.getText() + 
                  "Width = " + frame.getWidth() +
                  " Height = " + frame.getHeight() + "n");
        }//end propertyChange method
      }//end PropertyChangeListener constructor
    );//end addPropertyChangeListener method

Listing 7

To begin with, the code in Listing 7 makes use of an anonymous inner class. 
If you are unfamiliar with anonymous inner classes, see lessons number 1636, 1638, and 1640
at
http://www.dickbaldwin.com/tocmed.htm
.

The extra method parameter

The extra method parameter (relative to J2SE 5.0), which is a reference to the array object identifying the properties of interest is
shown in boldface in the first line in Listing 7.

The event handler method

The entire event handler method named propertyChange is shown in
boldface in Listing 7.  When one of the property values of interest
changes, this method is invoked.  The behavior of the method is to:

  • Get the current String contents of the TextArea object.
  • Get the new width and height values of the Frame object.
  • Construct a new String object in which the new information is
    concatenated onto the old information.
  • Replace the old String in the TextArea object with the new
    updated String object.

Make it all visible

Finally, the code in Listing 8 causes the Frame object, and its contents (a
TextArea object)
to become visible in the browser window.

    frame.setVisible(true);
  }//end main
}//end class WebApp003

Listing 8

Put it to work

From this point forward, if you manually change the size of the browser, you
will also change the size of the Frame object that contains the entire browser window.  This, in turn will cause the property values for width,
height, or both to change, causing a PropertyChangeEvent to be fired,
triggering the behavior described above.

Listing 8 also signals the end of the main method and the class named
WebApp003.

Compile and deploy the web application

You should be able to compile this program to produce the required class
files for the servlets that constitute the web application.  Then, you
should be able to create the required web.xml file and deploy the web
application in your favorite servlet container.

Having done that, you should be able to access the web application via your
browser and confirm the behavior described above.

A caution regarding browsers

If you are using any browser other than Internet Explorer, see the caution
regarding browsers at the top of Listing 25.  The people at ThinWire are
working to correct whatever it is that is causing this problem.  Hopefully,
it will be resolved in the next release.

And that concludes the discussion of the web application named WebApp003.

The Web Application Named WebApp004

Behavior of the Web Application

I described the general behavior of this web application
earlier
, so I won’t repeat that explanation here.

The Tomcat directory structure

Given what you already know about Tomcat directory structures, there is
nothing about the directory structure for this application that is new or
unusual, so I won’t bore you with additional discussion on that topic.

The Java source code

A complete listing of the Java source code for this web application is shown
in Listing 26 near the end of the lesson.  As before, I will discuss and
explain the source code in fragments.  The first such fragment is presented
in Listing 9.

Beginning of the class definition

Except for the name of the class, this application begins just like the
previous application.  The code in Listing 9 is essentially the same as the
code in Listing 2 and Listing 3, so there would be no point in repeating that
discussion.

public class WebApp004{
  public static void main(String[] args){
    final Frame frame = Application.current().getFrame();
    frame.setTitle("Action and PropertyChangeEvent Test");

Listing 9

Instantiate the four Button objects

Listing 10 instantiates the four Button objects shown at the top
of
Figure 3.

    Button moreWidth = new Button("Increase Width");
    moreWidth.setBounds(0,0,100,25);
    
    Button lessWidth = new Button("Decrease Width");
    lessWidth.setBounds(110,0,100,25);
    
    Button moreHeight = new Button("Increase Height");
    moreHeight.setBounds(0,35,100,25);
    
    Button lessHeight = new Button("Decrease Height");
    lessHeight.setBounds(110,35,100,25);

Listing 10

You will recall from the earlier description that
these buttons are used to modify the width and height of the text area also
shown in Figure 3.

Set the location and size of buttons

In addition to instantiating the objects, Listing 10 invokes the setBounds
method on each new button to establish its location and size in pixels relative
to the upper-left corner of the client area of the browser.

(The setBounds method is part of the
standard J2SE 5.0 library.  The parameters to the method are given in
absolute pixels.)

Create the TextArea object

Listing 11 instantiates the TextArea object shown in the bottom half
of Figure 3.

    final TextArea textArea = new TextArea(
                        "TextArea Size is Displayed Here");
    textArea.setBounds(0,80,200,100);
    textArea.setEnabled(false);

Listing 11

In addition, Listing 11:

  • Sets the size and position of the TextArea object within the
    Frame
    object.
  • Establishes the text that initially appears in the TextArea
    object.
  • Disables the TextArea object to prevent the user from entering text
    into it.  The object is being used solely for display purposes in this
    application.

Register an ActionListener on the first Button
object

Listing 12 registers an ActionListener object on the top left-most
Button
object shown in Figure 3.

    moreWidth.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
          textArea.setWidth(textArea.getWidth() + 10);
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener

Listing 12

Most of the earlier comments apply

Most of the comments that I made
earlier regarding the
addPropertyChangeListener
method apply also to the addActionListener
method
used in Listing 12.  The biggest difference
between the two is the number of possible
strings that can be passed as the first parameter to the method.  Whereas
there are dozens of properties that can be monitored by a listener, as of
ThinWire version 1.2 beta, there is only one action
that can be monitored.  As shown in
Listing 12, that action is specified by the named
constant Button.ACTION_CLICK.

Firing an ActionEvent

Whenever the user clicks the upper-left button in Figure 3 (or presses the
space bar while that button has the focus)
, the button will fire an
ActionEvent
.  This will cause the actionPerformed method
highlighted in boldface in Listing 12 to be executed, increasing the value of
the width property on the TextArea object by 10 pixels.

Firing a PropertyChangeEvent

In addition to causing the TextArea to become visibly wider, this will
cause the TextArea object to fire a PropertyChangeEvent.  We
will see the result of that event having been fired a little later.

Register ActionListener objects on the remaining
three buttons

Listing 13 does essentially the same thing to the remaining three buttons
shown in Figure 3.

    lessWidth.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
         textArea.setWidth(textArea.getWidth() - 10);
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener 
    
    moreHeight.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
         textArea.setHeight(textArea.getHeight() + 10);
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener
    
    lessHeight.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
         textArea.setHeight(textArea.getHeight() - 10);
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener

Listing 13

Once the code in Listing 13 has been executed, all four buttons will be
prepared to fire an ActionEvent if it is clicked.  The behavior of
each of the actionPerformed methods is slightly different, but each one
causes a change to either the width property or the height of the
TextArea object.

Register as PropertyChangeListener on the TextArea
object

The code in Listing 14 is essentially the same as the code that you saw in
Listing 6 and Listing 7, except this time we are registering the listener object
on the TextArea object instead of the Frame object.

    String[] properties = {TextArea.PROPERTY_WIDTH,
                           TextArea.PROPERTY_HEIGHT}; 

    textArea.addPropertyChangeListener(properties,
      new PropertyChangeListener(){
        public void propertyChange(PropertyChangeEvent e){
          textArea.setText(textArea.getText() + 
                      "nWidth = " + textArea.getWidth() +
                      " Height = " + textArea.getHeight());
        }//end propertyChange method
      }//end PropertyChangeListener constructor
    );//end addPropertyChangeListener method

Listing 14

Once again, what happens when the buttons are
clicked?

When any of the four buttons is clicked as described above, that will cause
the value of either the width property or the height property of
the TextArea object to change.  The TextArea object will fire a
PropertyChangeEvent
causing the propertyChange method defined in
Listing 14 to be executed.  The behavior of this event-handling method is
to concatenate the new width and height information onto the information already
in the TextArea and to store the new information back in the TextArea
object.

The new information will then appear in the visible window of the TextArea
object in Figure 3.

That’s almost a wrap

Listing 15 adds the components to the Frame.

    //Add the components to the Frame.
    frame.getChildren().add(moreWidth);
    frame.getChildren().add(lessWidth);
    frame.getChildren().add(moreHeight);
    frame.getChildren().add(lessHeight);    
    
    frame.getChildren().add(textArea);
    
    //Make the whole thing visible
    frame.setVisible(true);
  }//end main
}//end class WebApp004

Listing 15

Listing 15 also signals the end of the main method and the end of the
class named WebApp004.  And that is a wrap for WebApp004

The Web Application Named WebApp006

Behavior of the Web Application

I described the general behavior of this web application
earlier
, so I won’t repeat that explanation here.

The Tomcat directory structure

Given what you already know about the Tomcat directory structures, and given that
you have already seen Figure 5 that includes a directory named images,
there is nothing about the directory structure for this application that is new
or unusual.  However, I will need to refer back to the directory structure
for this application later, so I have provided the directory structure in
Figure 7.

Dir: WebApp006
.Dir: images
..redball.gif
.Dir: WEB-INF
..Dir: classes
...Dir: pkgdemo
....compile.bat
....WebApp006$1.class
....WebApp006.class
....WebApp006.java
..Dir: lib
...commons-fileupload.jar
...retroweaver-rt.jar
...thinwire.jar
..web.xml
Figure 7

The images directory in Figure 7 contains an image file named redball.gif,
which is used to put the red ball on the button in Figure 4.

The Java source code

A complete listing of the Java source code for this web application is shown
in Listing 27 near the end of the lesson.  As before, I will discuss and explain
that source code in fragments.  The first such fragment is shown in
Listing
16
.

Beginning of the class definition

As you can see in Listing 16, this program begins pretty much like the two
previous programs.  The one important difference is that this program also
imports classes from the directory named thinwire.ui.style, which was not
the case for the previous two programs.

package pkgdemo;

import thinwire.ui.*;
import thinwire.ui.event.*;
import thinwire.ui.style.*;

public class WebApp006{
  
  public static void main(String[] args){

    //Create a Frame object that will fill the client area
    // in the browser.
    final Frame frame = Application.current().getFrame();
    frame.setTitle("Compound Interest");//Browser title.

Listing 16

Configure the Label objects

Listing 17 instantiates and configures the three Label objects shown
across the top of the browser’s client window
in Figure 4.

    //Create, size, and position three Label objects.
    final Label depositLabel = new Label(
                                        "Monthly Deposit");
    depositLabel.setBounds(0,0,100,25);
    depositLabel.setAlignX(AlignX.CENTER);

    final Label rateLabel = new Label("Annual Rate");
    rateLabel.setBounds(110,0,100,25);
    rateLabel.setAlignX(AlignX.CENTER);
    
    final Label monthsLabel = new Label(
                                       "Number of Months");
    monthsLabel.setBounds(220,0,100,25);
    monthsLabel.setAlignX(AlignX.CENTER);

Listing 17

Given what you have learned so far, the code in Listing 17 is straightforward and shouldn’t require further
explanation.

The left-most TextField object

Figure 4 shows a row containing three TextField objects, followed by a
Button object on the right end of the row.

The red TextField object on the left will garner most of our attention
in this initial discussion.  The left-most TextField object is instantiated,
sized, and positioned in Listing 18.

    final TextField depositField = new TextField();
    depositField.setBounds(0,35,100,25);

Listing 18

There’s nothing remarkable about the code in Listing 18 so it doesn’t deserve
further discussion.  However, the code in Listing 19 is a different matter.

Set the style for the TextField object

In addition to about a dozen properties that can be set on a TextField
object (such as width, height, visible, enabled, etc.) a TextField
object also has about a dozen style parameters that can be set. 
This includes various choices for the background color, the font used for the
text, and three
choices regarding the border style (border type, border size, and border color).

Listing 19 illustrates the general procedure for setting the style of a
component.

    depositField.getStyle().getBackground().setColor(
                                                Color.RED);

    depositField.getStyle().getFont().setBold(true);

    depositField.getStyle().getBorder().setColor(
                                              Color.BLACK);
    depositField.getStyle().getBorder().setType(
                                       Border.Type.DOUBLE);

Listing 19

The getStyle method

Consider the first statement in Listing 19.  The getStyle method
is invoked on the TextField object, which, according to the javadocs,
"Returns a Style object representing this Component’s current style settings."

A Style object defines about eight methods, three of which are:

  • getBackground
  • getBorder
  • getFont

As you may have guessed, the getBackground method returns a reference
to an object of type Background.  The getBorder method
returns a reference to an object of type Border, and the getFont
method returns a reference to an object of type Font.

The Background object

The Background object defines several methods, one of which is
setColor
.  As you probably guessed already, the purpose of this method is to set the
background color of the component.  The
setColor
method requires a single parameter, which is a reference to an
object of type Color.

The Color class

The Color class is defined in J2SE 5.0, and is also defined in
ThinWire.  Thus, when coding with the ThinWire JAR files, the version that
is defined in ThinWire will prevail.

The J2SE 5.0 Color class defines about fifteen named color constants
such as RED, GREEN, BLUE, YELLOW, etc.  In addition, it defines some
methods that allow the program to generate any of about sixteen million
different colors by mixing the primary colors of red, green, and blue in
different proportions.

The ThinWire Color class does not provide the ability to mix the
primary colors, but it does define about 200 different named color constants,
such as RED, PEACHPUFF, PAPAYAWHIP, etc.  (I never knew there were so
many colors with names.)

Set the background color to RED

In the final analysis, the first statement in Listing 19 sets the background
color of the left-most TextField object in Figure 4 to RED, using a named
color constant from the Color class.

Set the style for the font and the border

I could go through a similar series of steps to explain that the second statement
in Listing 19 sets the font style for the leftmost TextField in Figure 4
to bold, but that would probably put you to sleep.

Finally, the last two statements in Listing 19 set the border color to BLACK
and set the border type to DOUBLE.

This general approach should suffice for setting the style on any
ThinWire GUI component
for which you have a choice of styles.

Create the remaining two TextField objects

Listing 20 instantiates, sizes, and positions the remaining two TextField
objects shown in Figure 4.

    final TextField rateField = new TextField();
    rateField.setBounds(110,35,100,25);
    
    final TextField termField = new TextField();
    termField.setBounds(220,35,100,25);

Listing 20

The default style was accepted for both of these TextField objects
so no further explanation should be required.

A Button with an image

The ThinWire Button class provides three overloaded constructors:

  • Button():  Constructs a new Button with no text or
    image.
  • Button(java.lang.String text):  Constructs a new Button
    with the specified text and no image.
  • Button(java.lang.String text, java.lang.String image)
    Constructs a new Button with the specified text and image.

Construct the Button with an image

The third constructor in the above list was used in the first statement in
Listing 21 to construct the Button with the red ball image shown
in
Figure 4.

    final Button okButton = new Button(
                                "OK","images/redball.gif");

    okButton.setBounds(330,35,100,25);

Listing 21

As you can see in listing 21, the second parameter passed to the constructor
was the name of the image file stored in the images directory shown in
Figure 7.

The second statement in Listing 21 simply sizes and positions the button to
the location shown in Figure 4.

Complete the GUI setup code

The code in Listing 22 completes the construction of the Graphical User
Interface shown in Figure 4.

    //Instantiate, size, and position a TextArea object. 
    // Disable the object so that the user cannot modify
    // the text.  It is being used as a display component
    // only in this program.
    final TextArea display = new TextArea("");
    display.setBounds(0,80,200,100);
    display.setEnabled(false);
    
    //Add all the components to the Frame, and hence to the
    // client area of the browser.  Note that the size
    // and location of each component is determined by the
    // invocation of the setBounds method on the component
    // earlier and is independent of the order in which the
    // components are added to the Frame.
    frame.getChildren().add(depositLabel);
    frame.getChildren().add(rateLabel);
    frame.getChildren().add(monthsLabel);
    
    frame.getChildren().add(depositField);
    frame.getChildren().add(rateField);
    frame.getChildren().add(termField);
    
    frame.getChildren().add(okButton);
    
    frame.getChildren().add(display);
    
    //Make the whole thing visible
    frame.setVisible(true);

Listing 22

By now, everything is Listing 22 should be familial to you, and should
not require an explanation beyond that provided by the comments.

Register an ActionListener on the Button

Recall that the purpose of this application is to do the following each time
the user clicks the button in Figure 4:

  • Fetch three user input values via the three TextField objects.
  • Perform a financial computation having to do with interest rates,
    monthly deposits, etc.
  • Display a table of results showing the results of that computation.

This is accomplished by the ActionEvent handler registered on the
button as shown in Listing 23.

    okButton.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
          try{
            //Convert contents of the text fields to
            // numeric data.  Watch out for invalid data
            // that can't be parsed into numeric data.
            double monthlyDeposit = Double.parseDouble(
                                   depositField.getText());
            double annualInterestRate = Double.parseDouble(
                                      rateField.getText());
            int numberMonths = Integer.parseInt(
                                      termField.getText());
            
            //Convert the rate from percent format to 
            //decimal format.  Also convert it from an
            // an annual rate to a monthly rate in the
            // process.
            double monthlyInterestRate =  
                                 annualInterestRate/1200.0;
            //Initialize the balance.
            double balance = 0.0;
            
            //Initialize the display.
            display.setText("Month / Balancen");
            
            //Process each month.
            for(int cnt = 0;cnt < numberMonths;cnt++){
              balance = balance + 
                        balance * monthlyInterestRate + 
                        monthlyDeposit;
              //Eliminate all but two digits to the right
              // of the decimal point in the display only.
              int temp = (int)(balance*100.0);
              double printBalance = temp/100.0;
              
              //Concatenate the new data onto the string
              // that already exists in the display.
              display.setText(display.getText() + 
                 (cnt + 1) + " / $" + printBalance + "n");
            }//end for loop
          }catch(NumberFormatException ex){
            //Deal with input data that can't be parsed
            // into numeric data.
            //Would be better to test each input field
            // individually and to put the error message in
            // the field with the bad data.  Could be done
            // by using three consecutive try-catch blocks,
            // one for each text field.
            depositField.setText("Entry error");
            display.setText("");
          }//end catch
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener
    
  }//end main
}//end class WebApp006

Listing 23

Won’t walk you through the code

I’m not going to walk you through the code.  The code in Listing 23 is
completely straightforward Java event-driven programming code.  Except for the
requirement for the extra parameter passed to the addActionListener
method, nothing about this code is peculiar to ThinWire.  Either you already under stand
Java event-driven programming or you don’t, and if you don’t, you should avail
yourself of the programming tutorials on my
web site.

Listing 23 also signals the end of the main method and the end of the
WebApp006 class.

And, that wraps up the explanation of the web application named WebApp006.

The Web Application Named WebApp008

A poor programming style

The first three web applications in this tutorial use a poor Java programming
style.  In particular, all of the executable code for each of those three
programs is contained in the main method.  While this is a quick and
dirty way to throw some Java code together to get something running, it is a
poor style from an object-oriented programming viewpoint.

Not a ThinWire requirement

I didn’t want you to leave this lesson believing that the ThinWire
framework
requires you to use a poor programming style.  Rather, the ThinWire
framework is compatible
with the best Java programming style that you can muster.

A program rewrite

As a demonstration that ThinWire is
compatible with an improved programming style, WebApp008 is a rewrite of
WebApp006 but written in a much better style.  In particular, as you
can see in Listing 24, the main method in WebApp008 consists of a
single statement, which instantiates an object of the class named
GUI
.

public class WebApp008{
  public static void main(String[] args){
    new GUI();
  }//end main
}//end class WebApp008

Listing 24

With the exception of the single statement in Listing 24, all of the
executable Java code was moved into the class named GUI.  From that point,
if the size of the program were to justify doing so, you could define many new
classes and instantiate many new objects in order to accomplish your
object-oriented programming
goals.

Just write a standalone Java application

To create a ThinWire web application,
just write your web application as though you were writing a standalone Java
application using the best programming style that you know how to write. 
The ThinWire framework will take care of turning it into a web application when
you compile it.

Once again, I won’t walk you through the code

Since this is not a tutorial on how to program in Java, I’m not going to walk
you through the code in WebApp008.  Except for the overall
organization, this code is essentially the same as the code that I explained in
conjunction with WebApp006.  Rather, I will simply refer you to a
complete listing of the program, which you will find in Listing 28.

The same behavior

The behavior of WebApp008 is the same as WebApp006
However, as you can see by comparing Figure 5 with Figure 7, this application does create a couple of additional class files in the
pkgdemo
directory.  Regardless of the number of class files, deployment
of this web application into the servlet container is the same as deployment of the first
three web applications in this lesson.

Check with your server administrator

Your server administrator can tell you the best way to deploy the
application, depending on the type of servlet container being used. 
However, for test purposes, you can deploy the application onto a Tomcat server
running as localhost simply by copying the directory tree named WebApp008
from your development tree into the webapps directory of the server, just
like for the first three applications.

And that’s about all I need to say about the web application named
WebApp008.

Run the Program

I encourage you to download
the ThinWire framework and the
Jakarta Tomcat server and give them a try. 
Copy my code from Listing 25 through Listing 28 and compile it being sure to
have the ThinWire JAR files at the
beginning of your classpath.  Then deploy the resulting
web applications onto the Tomcat server and test them using your favorite
browser.

Experiment with my code, making changes and observing the results of your
changes.  Learn how to write web applications using this exciting new
technology.  Above all, enjoy the process.  Programming can be fun.

Summary

ThinWire makes it as easy to develop rich web applications as it is to write
standalone Java applications.  Once you have a correctly written Java
application all that is necessary to build the web application is to:

Compile your Java application using Sun’s javac compiler with the
three ThinWire JAR files at the
beginning of the classpath.

That’s all there is to it.  It’s that simple.

Late Breaking Information

I have received invaluable cooperation from members of the
ThinWire development and support team during my efforts to learn about the
ThinWire framework and to write this tutorial. 
Because this framework is in the very early stages of development, the situation is
fairly fluid and things can change very rapidly.

Release of ThinWire version 1.2 beta2

I will be submitting this tutorial lesson to my publisher
later today for publication on or about August 22, 2006.  All of the sample web applications and all of the discussion
in this tutorial were based on ThinWire version 1.2 beta.  I was notified a few
minutes ago that ThinWire version 1.2 beta2 was released earlier today.  The text of
the release message, which I received from the ThinWire team via email, is
presented in Figure 8.

Beta2 is now available for
download at

http://thinwire.com/download.html
and there is a full changelog
at

https://sourceforge.net/project/shownotes.php?release_id=437788&group_id=170706

We have also updated our demos and made the demo server public.  There
is a decent summary on the thinwire blog.

Figure 8

The ThinWire blog mentioned in the message is located at
http://thinwire.com/blog/.

Comments from the ThinWire team

Several days ago, I submitted a copy of this tutorial to the ThinWire team
for their review and comments because I want to be as accurate as possible in
my depiction of their framework.  Because the
javadocs for ThinWire version 1.2 beta were still somewhat lacking in detail
when this tutorial was being written, the information contained
herein was sometimes based on my best interpretation at the time.

Today I received very welcome feedback and comments from the ThinWire team.  I have
decided that rather than to provide my own interpretation of their comments, I
will simply present those comments to you verbatim.  The comments are
provided for your review in Figure 9 below.

First, the three JAR files:

  • thinwire.jar is the ThinWire framework, the other 2 JAR files
    are 3rd party libraries, and are not technically part of the
    framework
  • commons-fileupload.jar is from the Apache Commons, and provides
    the ability for our FileChooser component to upload files to the
    server. (http://jakarta.apache.org/commons/fileupload/)
  • retroweaver-rt.jar is a runtime library that enables ThinWire to
    work with J2SE 1.4 (The ThinWire sources are written using Java 1.5
    specific features like generics, and retroweaver allows us to
    backport to support Java 1.4) (http://retroweaver.sourceforge.net/)

Second, the web.xml file and main method

There is no requirement that the class that contains the main method
have the application name.  In fact, the main method for the Playground
is in a class called Main.  What is required is that you specify the
class that contains your main method in the web.xml as follows:

<init-param>
    <param-name>mainClass</param-name>
    <param-value>package.and.class.containing.main.method</param-value>
</init-param>

So, for the Playground, the main method is in Main.java which is in the
package thinwire.apps.playground.  The web.xml entry would be:

<init-param>
    <param-name>mainClass</param-name>
    <param-value>thinwire.apps.playground.Main</param-value>
</init-param>

Third, the Color class

You mentioned that the AWT Color class allows you to specify mixtures of
red green and blue to create any color.  The ThinWire Color class
provides this ability as well.  The static method valueOf(String colorId)
accepts rgb values in the form: "rgb(r, g, b)", as well as the HEX
values (ex: "#5F9EA0").  The predefined constants mirror the color
constants supported by CSS.

Finally, a philosophical point

We don’t view the ThinWire api as set
of overloaded Swing components.  We view ThinWire as it’s own UI widget
set.  The only thing it shares with Swing or AWT or SWT (or MFC or
Cocoa, etc) are the names and general concepts of GUI components
(buttons, text fields, etc).

On behalf of (team member names deleted for privacy) and myself, thanks for creating these tutorials.  We
are very excited about their publication on
developer.com, and are hopeful that they show many people how easy
Rich Internet Application programming can be with ThinWire.  Please
continue to send us your questions and we will continue to help you to
the best of our ability. 

Figure 9

What’s Next?

I hope that you have found this tutorial on Getting Started with ThinWire
useful.  Although my plans often change over time for a variety of reasons,
at this time I plan to publish a series of tutorial lessons on using ThinWire
that will include the following topics:

  • GUI components
  • The ThinWire Playground tool
  • Layout
  • The Visual Form Creator tool
  • Interaction with JDBC and  MySQL
  • Dealing with large images

In addition, I also plan to publish tutorial lessons on developing web
applications using competing technologies such as the
Google Web Toolkit,
(GWT)
.

Complete Program Listings


Complete listings of the web applications discussed in this lesson are shown in
Listing 25 through Listing 28 below.
 

/*File WebApp003.java
Copyright 2006, R.G.Baldwin

This is a sample ThinWire web application that illustrates 
PropertyChangeEvent handling on a Frame object.

Caution:  As of ThinWire v1.2 beta, this application will 
not execute properly under either Firefox v 1.5.0.5 or
Netscape 7.2.  In both cases, an instability appears when 
the size of the frame is changed using the handle at the 
lower right of the frame.  However, it executes properly 
under Internet Explorer v6.0.xx.

Instantiates a Frame object that fills the entire browser 
window.  

Places a disabled TextArea in the Frame.

Registers a PropertyChangeListener on the Frame, listening 
for a change in either the width or the height of the 
Frame.

When the browser is manually resized, the size of the 
Frame also changes because the Frame fills the entire 
client window of the browser.  This causes a 
PropertyChangeEvent to be fired by the Frame.  The event 
handler displays the new width and height in the TextArea,
concatenating them onto the text that was already there 
with a line break separating the new material from the old
material.

When the TextArea becomes full, a vertical scroll bar 
automatically appears.

Note that the addPropertyChangeListener method in ThinWire
is different from J2SE 5.0.

Registration methods in ThinWire have an extra parameter.
The extra parameter is a String object or an array of 
String objects that identify the things that are to be
monitored by the listener object.

Also note that the syntax required to create a new Frame
object, and the syntax for adding a component to a 
Frame object is different between the ThinWire API and
J2SE 5.0.

Tested using J2SE 5.0, ThinWire 1.2 Beta, and 
jakarta-tomcat-5.0.27 under WinXP.
**********************************************************/

package pkgdemo;

import thinwire.ui.*;
import thinwire.ui.event.*;

public class WebApp003{
  public static void main(String[] args){
    //Note that this approach to getting a Frame object is
    // different from the approach used in J2SE 5.0.
    final Frame frame = Application.current().getFrame();
    //The following title becomes the title in the banner
    // of the browser, and also the title of the tab in
    // a Firefox tabbed browser.
    frame.setTitle("PropertyChangeEvent Test");
    
    final TextArea textArea = new TextArea(
                         "Frame Size is Displayed Heren");
    textArea.setBounds(0,0,200,200);
    textArea.setEnabled(false);
    
    //Note the unusual syntax, (relative to J2SE 5.0),
    // that is required to add a component to the frame.
    frame.getChildren().add(textArea);
    
    //Create an array object containing the properties
    // for which changes will be detected by the listener
    // to be registered on the frame.
    String[] properties = {Frame.PROPERTY_WIDTH,
                           Frame.PROPERTY_HEIGHT};
                           
    //Note the somewhat unusual (relative to J2SE 5.0) 
    // first parameter in the following method call that
    // registers a listener on the frame.
    frame.addPropertyChangeListener(properties,
      new PropertyChangeListener(){
        public void propertyChange(PropertyChangeEvent e){
          textArea.setText(textArea.getText() + 
                  "Width = " + frame.getWidth() +
                  " Height = " + frame.getHeight() + "n");
        }//end propertyChange method
      }//end PropertyChangeListener constructor
    );//end addPropertyChangeListener method
    
    frame.setVisible(true);
  }//end main
}//end class WebApp003

Listing 25

Listing 26

/*File WebApp004.java
Copyright 2006, R.G.Baldwin

This program illustrates the use of ThinWire to create a
web application.

Illustrates ActionEvent handling on a Button and 
PropertyChangeEvent handling on a TextArea object.

Note that the addActionListener and 
addPropertyChangeListener methods in ThinWire are different
from those in J2SE 5.0.

These two methods in ThinWire have an extra parameter.  The
extra parameter is a String object or an array of String 
objects that specify actions or properties, depending on 
the specific method involved.

As of ThinWire v1.2 Beta, there is only one kind of action 
and it is specified as ACTION_CLICK.  However, there are 
dozens of different properties that apply in different 
combinations to different components.

This program uses PROPERTY_WIDTH and PROPERTY_HEIGHT.

The action registration method registers a listener on the 
component that will be notified when the specified action 
occurs.

The property registration method registers a listener on 
the component that will be notified when any of the 
specified properties change.

This program places four buttons and a disabled TextArea 
object in a Frame that fills the entire browser window.

Anonymous ActionEvent handlers are registered on each of 
the buttons.  Two of the buttons increase and decrease the 
width of the text area.  The other two buttons increase and
decrease the height of the text area.

An anonymous PropertyChangeListener is registered on the 
TextArea object, listening for a change in either the width
or the height of the text area.  

Changing the width or the height of the text area causes a 
PropertyChangeEvent to be fired.  The event handler 
displays the new width and height in the TextArea, 
concatenating them onto the text that was already there 
with a line break separating the new material from the old 
material.

When the TextArea becomes full, a vertical scroll bar 
automatically appears.  However, I could find no way to 
cause it to automatically scroll to the bottom so as to 
display the newest material.

When the width of the text area is decreased to less than
the length of the longest line of text, a horizontal scroll
bar does not appear.  Rather, the text wraps to the next
line, and appears to wrap correctly at word boundaries.
However, when the width of the text area becomes less than
the length of the longest word, a horizontal scroll bar
appears automatically.

Tested using J2SE 5.0, ThinWire 1.2 Beta, and 
jakarta-tomcat-5.0.27 under WinXP.
**********************************************************/

package pkgdemo;

import thinwire.ui.*;
import thinwire.ui.event.*;

public class WebApp004{
  public static void main(String[] args){
    //Note that this approach to getting a Frame object is
    // different from the approach used in J2SE 5.0.
    final Frame frame = Application.current().getFrame();
    //The following title becomes the title in the banner
    // of the browser, and also the title of the tab in
    // a Firefox tabbed browser.
    frame.setTitle("Action and PropertyChangeEvent Test");
    
    //Instantiate the four buttons that are used to modify
    // the width and height of the text area.  Note that
    // the position and size of the buttons in the
    // browser window is specified in absolute pixel
    // coordinates relative to the upper-left corner of the
    // browser window.
    Button moreWidth = new Button("Increase Width");
    moreWidth.setBounds(0,0,100,25);
    
    Button lessWidth = new Button("Decrease Width");
    lessWidth.setBounds(110,0,100,25);
    
    
    Button moreHeight = new Button("Increase Height");
    moreHeight.setBounds(0,35,100,25);
    
    Button lessHeight = new Button("Decrease Height");
    lessHeight.setBounds(110,35,100,25);
    
    //Instantiate, position, and set the size of the text
    // area.  Provide initial text for the text area.
    // Disable the text area so that the user cannot modify
    // the text.  It is being used as a display component
    // only in this program.
    final TextArea textArea = new TextArea(
                        "TextArea Size is Displayed Here");
    textArea.setBounds(0,80,200,100);
    textArea.setEnabled(false);
    
    //Note the somewhat unusual (relative to J2SE 5.0) 
    // first parameter in the following method calls that
    // register action listeners on the buttons.  (See
    // earlier comments.)
    moreWidth.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
         textArea.setWidth(textArea.getWidth() + 10);
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener
    
    lessWidth.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
         textArea.setWidth(textArea.getWidth() - 10);
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener 
    
    moreHeight.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
         textArea.setHeight(textArea.getHeight() + 10);
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener
    
    lessHeight.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
         textArea.setHeight(textArea.getHeight() - 10);
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener
    
    //Create an array object containing the properties
    // for which changes will be detected by the listener
    // to be registered on the text area.
    String[] properties = {TextArea.PROPERTY_WIDTH,
                           TextArea.PROPERTY_HEIGHT}; 
    //Note the somewhat unusual (relative to J2SE 5.0) 
    // first parameter in the following method call.
    textArea.addPropertyChangeListener(properties,
      new PropertyChangeListener(){
        public void propertyChange(PropertyChangeEvent e){
          textArea.setText(textArea.getText() + 
                      "nWidth = " + textArea.getWidth() +
                      " Height = " + textArea.getHeight());
        }//end propertyChange method
      }//end PropertyChangeListener constructor
    );//end addPropertyChangeListener method
    
    //Add the components to the Frame.
    frame.getChildren().add(moreWidth);
    frame.getChildren().add(lessWidth);
    frame.getChildren().add(moreHeight);
    frame.getChildren().add(lessHeight);    
    
    frame.getChildren().add(textArea);
    
    //Make the whole thing visible
    frame.setVisible(true);
  }//end main
}//end class WebApp004


Listing 26

Listing 27

/*File WebApp006.java
Copyright 2006, R.G.Baldwin

This program illustrates the use of ThinWire to create a
web application.

Caution:  As of ThinWire v1.2 beta, this application will 
not execute properly under either Firefox v 1.5.0.5 or
Netscape 7.2.  In both cases, an instability appears when 
the text area is updated.  In addition, in Netscape 7.2, 
the use of the tab key to traverse the components results 
in the focus hitting only every second component.

However, neither problem exists with Internet Explorer 
v6.0xx.  The program executes properly under Internet 
Explorer v6.0.xx.

Illustrates the ability to use the power of server-side
Java to provide a computational service to a client as a 
web application.

Assumes a monthly deposit of a fixed amount into a
savings account for a fixed number of months, at a fixed
annual percentage rate.

Places three TextField objects, a Button object, and a 
TextArea object in a Frame object (along with some Label 
objects for cosmetic purposes).  Note that there is an 
image on the Button.

Gets Monthly Deposit, Annual Percentage Rate, and Number of
Months from the client via the TextField objects.  Each 
time the user clicks the OK button, the program computes
and displays a table in the TextArea showing the balance 
at the end of each month, 

Tested using J2SE 5.0, ThinWire 1.2 Beta, and 
jakarta-tomcat-5.0.27 under WinXP.
**********************************************************/

package pkgdemo;

import thinwire.ui.*;
import thinwire.ui.event.*;
import thinwire.ui.style.*;

public class WebApp006{
  
  public static void main(String[] args){

    //Create a Frame object that will fill the client area
    // in the browser.
    final Frame frame = Application.current().getFrame();
    frame.setTitle("Compound Interest");//Browser title.
    
    //Create, size, and position three Label objects.
    final Label depositLabel = new Label(
                                        "Monthly Deposit");
    depositLabel.setBounds(0,0,100,25);
    depositLabel.setAlignX(AlignX.CENTER);

    final Label rateLabel = new Label("Annual Rate");
    rateLabel.setBounds(110,0,100,25);
    rateLabel.setAlignX(AlignX.CENTER);
    
    final Label monthsLabel = new Label(
                                       "Number of Months");
    monthsLabel.setBounds(220,0,100,25);
    monthsLabel.setAlignX(AlignX.CENTER);
    
    //Create, size, and position a TextField object and set
    // the style of the TextField.
    final TextField depositField = new TextField();
    depositField.setBounds(0,35,100,25);
    
    //Illustrate how to set the style of a component.
    depositField.getStyle().getBackground().setColor(
                                                Color.RED);
    depositField.getStyle().getFont().setBold(true);
    depositField.getStyle().getBorder().setColor(
                                              Color.BLACK);
    depositField.getStyle().getBorder().setType(
                                       Border.Type.DOUBLE);
    
    //Create, size, and position two more TextField objects
    // and a Button object.  Accept the default style for
    // each.  Note that there is an image on the Button.
    final TextField rateField = new TextField();
    rateField.setBounds(110,35,100,25);
    
    final TextField termField = new TextField();
    termField.setBounds(220,35,100,25);
    
    //Note the format of the constructor parameter list to
    // place an image on the button.
    final Button okButton = new Button(
                                "OK","images/redball.gif");
    okButton.setBounds(330,35,100,25);
    
    //Instantiate, size, and position a TextArea object. 
    // Disable the object so that the user cannot modify
    // the text.  It is being used as a display component
    // only in this program.
    final TextArea display = new TextArea("");
    display.setBounds(0,80,200,100);
    display.setEnabled(false);
    
    //Add all the components to the Frame, and hence to the
    // client area of the browser.  Note that the size
    // and location of each component is determined by the
    // invocation of the setBounds method on the component
    // earlier and is independent of the order in which the
    // components are added to the Frame.
    frame.getChildren().add(depositLabel);
    frame.getChildren().add(rateLabel);
    frame.getChildren().add(monthsLabel);
    
    frame.getChildren().add(depositField);
    frame.getChildren().add(rateField);
    frame.getChildren().add(termField);
    
    frame.getChildren().add(okButton);
    
    frame.getChildren().add(display);
    
    //Make the whole thing visible
    frame.setVisible(true);
    
    
    //Define and register an action listener on the
    // okButton.  The purpose of this event handler is to
    // get the relevant information from the user and use
    // that information to compute and display a table
    // showing monthly balances in the savings account.
    okButton.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
          try{
            //Convert contents of the text fields to
            // numeric data.  Watch out for invalid data
            // that can't be parsed into numeric data.
            double monthlyDeposit = Double.parseDouble(
                                   depositField.getText());
            double annualInterestRate = Double.parseDouble(
                                      rateField.getText());
            int numberMonths = Integer.parseInt(
                                      termField.getText());
            
            //Convert the rate from percent format to 
            //decimal format.  Also convert it from an
            // an annual rate to a monthly rate in the
            // process.
            double monthlyInterestRate =  
                                 annualInterestRate/1200.0;
            //Initialize the balance.
            double balance = 0.0;
            
            //Initialize the display.
            display.setText("Month / Balancen");
            
            //Process each month.
            for(int cnt = 0;cnt < numberMonths;cnt++){
              balance = balance + 
                        balance * monthlyInterestRate + 
                        monthlyDeposit;
              //Eliminate all but two digits to the right
              // of the decimal point in the display only.
              int temp = (int)(balance*100.0);
              double printBalance = temp/100.0;
              
              //Concatenate the new data onto the string
              // that already exists in the display.
              display.setText(display.getText() + 
                 (cnt + 1) + " / $" + printBalance + "n");
            }//end for loop
          }catch(NumberFormatException ex){
            //Deal with input data that can't be parsed
            // into numeric data.
            //Would be better to test each input field
            // individually and to put the error message in
            // the field with the bad data.  Could be done
            // by using three consecutive try-catch blocks,
            // one for each text field.
            depositField.setText("Entry error");
            display.setText("");
          }//end catch
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener
    
  }//end main
}//end class WebApp006


Listing 27

Listing 28

/*File WebApp008.java
Copyright 2006, R.G.Baldwin

This program illustrates the use of ThinWire to create a
web application.

This program is an update to the earlier program named
WebApp006.  The sole purpose of this update is to move
most of the code from the main method into another class.
The behavior should not be changed relative to the behavior
of the earlier program.

Caution:  As of ThinWire v1.2 beta, this application will 
not execute properly under either Firefox v 1.5.0.5 or
Netscape 7.2.  In both cases, an instability appears when 
the text area is updated.  In addition, in Netscape 7.2, 
the use of the tab key to traverse the components results 
in the focus hitting only every second component.

However, neither problem exists with Internet Explorer 
v6.0xx.  The program executes properly under Internet 
Explorer v6.0.xx.

Illustrates the ability to use the power of server-side
Java to provide a computational service to a client as a 
web application.  Also illustrates control over
the style of GUI component, and images on buttons.

Assumes a monthly deposit of a fixed amount into a
savings account for a fixed number of months, at a fixed
annual percentage rate.

Places three TextField objects, a Button object, and a 
TextArea object in a Frame object (along with some Label 
objects for cosmetic purposes).  Note that there is an 
image on the Button.

Gets Monthly Deposit, Annual Percentage Rate, and Number of
Months from the client via the TextField objects.  Each 
time the user clicks the OK button, the program computes
and displays a table in the TextArea showing the balance 
at the end of each month, 

Tested using J2SE 5.0, ThinWire 1.2 Beta, and 
jakarta-tomcat-5.0.27 under WinXP.
**********************************************************/

package pkgdemo;

import thinwire.ui.*;
import thinwire.ui.event.*;
import thinwire.ui.style.*;

public class WebApp008{
  
  public static void main(String[] args){
    new GUI();
  }//end main
}//end class WebApp008
//=======================================================//

class GUI{
  GUI(){//constructor
  
    //Create a Frame object that will fill the client area
    // in the browser.
    final Frame frame = Application.current().getFrame();
    frame.setTitle("Compound Interest");//Browser title.
    
    //Create, size, and position three Label objects.
    final Label depositLabel = new Label(
                                        "Monthly Deposit");
    depositLabel.setBounds(0,0,100,25);
    depositLabel.setAlignX(AlignX.CENTER);

    final Label rateLabel = new Label("Annual Rate");
    rateLabel.setBounds(110,0,100,25);
    rateLabel.setAlignX(AlignX.CENTER);
    
    final Label monthsLabel = new Label(
                                       "Number of Months");
    monthsLabel.setBounds(220,0,100,25);
    monthsLabel.setAlignX(AlignX.CENTER);
    
    //Create, size, and position a TextField object and set
    // the style of the TextField.
    final TextField depositField = new TextField();
    depositField.setBounds(0,35,100,25);
    
    //Illustrate how to set the style of a component.
    depositField.getStyle().getBackground().setColor(
                                                Color.RED);
    depositField.getStyle().getFont().setBold(true);
    depositField.getStyle().getBorder().setColor(
                                              Color.BLACK);
    depositField.getStyle().getBorder().setType(
                                       Border.Type.DOUBLE);
    
    //Create, size, and position two more TextField objects
    // and a Button object.  Accept the default style for
    // each.  Note that there is an image on the Button.
    final TextField rateField = new TextField();
    rateField.setBounds(110,35,100,25);
    
    final TextField termField = new TextField();
    termField.setBounds(220,35,100,25);
    
    //Note the format of the constructor parameter list to
    // place an image on the button.
    final Button okButton = new Button(
                                "OK","images/redball.gif");
    okButton.setBounds(330,35,100,25);
    
    //Instantiate, size, and position a TextArea object. 
    // Disable the object so that the user cannot modify
    // the text.  It is being used as a display component
    // only in this program.
    final TextArea display = new TextArea("");
    display.setBounds(0,80,200,100);
    display.setEnabled(false);
    
    //Add all the components to the Frame, and hence to the
    // client area of the browser.  Note that the size
    // and location of each component is determined by the
    // invocation of the setBounds method on the component
    // earlier and is independent of the order in which the
    // components are added to the Frame.
    frame.getChildren().add(depositLabel);
    frame.getChildren().add(rateLabel);
    frame.getChildren().add(monthsLabel);
    
    frame.getChildren().add(depositField);
    frame.getChildren().add(rateField);
    frame.getChildren().add(termField);
    
    frame.getChildren().add(okButton);
    
    frame.getChildren().add(display);
    
    //Make the whole thing visible
    frame.setVisible(true);
    
    
    //Define and register an action listener on the
    // okButton.  The purpose of this event handler is to
    // get the relevant information from the user and use
    // that information to compute and display a table
    // showing monthly balances in the savings account.
    okButton.addActionListener(Button.ACTION_CLICK,
      new ActionListener(){
        public void actionPerformed(ActionEvent e){
          try{
            //Convert contents of the text fields to
            // numeric data.  Watch out for invalid data
            // that can't be parsed into numeric data.
            double monthlyDeposit = Double.parseDouble(
                                   depositField.getText());
            double annualInterestRate = Double.parseDouble(
                                      rateField.getText());
            int numberMonths = Integer.parseInt(
                                      termField.getText());
            
            //Convert the rate from percent format to 
            //decimal format.  Also convert it from an
            // an annual rate to a monthly rate in the
            // process.
            double monthlyInterestRate =  
                                 annualInterestRate/1200.0;
            //Initialize the balance.
            double balance = 0.0;
            
            //Initialize the display.
            display.setText("Month / Balancen");
            
            //Process each month.
            for(int cnt = 0;cnt < numberMonths;cnt++){
              balance = balance + 
                        balance * monthlyInterestRate + 
                        monthlyDeposit;
              //Eliminate all but two digits to the right
              // of the decimal point in the display only.
              int temp = (int)(balance*100.0);
              double printBalance = temp/100.0;
              
              //Concatenate the new data onto the string
              // that already exists in the display.
              display.setText(display.getText() + 
                 (cnt + 1) + " / $" + printBalance + "n");
            }//end for loop
          }catch(NumberFormatException ex){
            //Deal with input data that can't be parsed
            // into numeric data.
            //Would be better to test each input field
            // individually and to put the error message in
            // the field with the bad data.  Could be done
            // by using three consecutive try-catch blocks,
            // one for each text field.
            depositField.setText("Entry error");
            display.setText("");
          }//end catch
        }//end actionPerformed
      }//end ActionListener constructor
    );//end addActionListener
  
  }//end constructor
}//end class GUI


Listing 28


Copyright 2006, Richard G. Baldwin.  Reproduction in whole or in part in any
form or medium without express written permission from Richard Baldwin is
prohibited.

About the author

Richard Baldwin is a
college professor (at Austin Community College in Austin, TX) and private
consultant whose primary focus is a combination of Java, C#, and XML. In
addition to the many platform and/or language independent benefits of Java and
C# applications, he believes that a combination of Java, C#, and XML will become
the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he
frequently provides onsite training at the high-tech companies located in and
around Austin, Texas.  He is the author of Baldwin’s Programming
Tutorials, which have gained a
worldwide following among experienced and aspiring programmers. He has also
published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of
practical experience in Digital Signal Processing (DSP).  His first job after he
earned his Bachelor’s degree was doing DSP in the Seismic Research Department of
Texas Instruments.  (TI is still a world leader in DSP.)  In the following
years, he applied his programming and DSP expertise to other interesting areas
including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has
many years of experience in the application of computer technology to real-world
problems.

Baldwin@DickBaldwin.com

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories