PHD Computer Consultants Ltd
... Practical Java article
Last modified: 1 November 1996.

Reconstructed. Approx 4600 words, including code snippets.

Referenced pages: sidebars/figures in article.

Text in <CODE> tags are class names, while those in <TT> tags are methods.

When published, HTML links in the text can be removed.

Practical Java

Introduction

This article is a collection of useful - some important - tips for using Java picked up when writing my HelpIndex applet for use in World Wide Web browsers. I assume some basic familiarity with Java.

When writing an applet from scratch, you will want to decide which base classes to use, how best to use the windowing classes AWT, what techniques are appropriate when programming an applet and the differences between the main PC browsers. Sidebars discuss how to do anything useful, Java pros and cons, APIs and IDEs.

PHD's HelpIndex applet reads a list of index keywords (and their links to web pages) from the host. Like various help systems, the user can type in the first few letters of their search string. The matching indices and their pages are listed automatically. The selected page can be displayed. The companion MakeHelpIndex Java application lets you build a help index file from your existing web pages.

Figure 1 shows a screen shot showing that the user has typed in J and all the matching keyword indices have been found. Java applet has been selected and various matching pages have been found. HelpIndex Java Applet is selected, so pressing Display Page will show this page. A standard server based search for Java on the PHD site threw up over 200 hits; it would be difficult to know which page to go to.

Figure 1.

Incidentally, one good use of HelpIndex is to provide an index for all the fields and methods of an API. The standard JDK javadoc program is used to produce web page documentation for an API from suitable source code comments. One of its standard outputs is an alphabetical listing of all fields and methods. If you want to look up the getAddress() method, then you have to click on the G short-cut link at the top of the page, then scroll down through all the get() methods until finally you get to where you want. PHD HelpIndex allows you simply to type in get; then the get() and getAddress() methods are listed as indices - much easier.

Before you start

If something goes wrong remember that Java is a young language and its API classes are relatively new too. So, always remember to check Sun's known bugs at http://java.sun.com/products/JDK/CurrentRelease/KnownBugs.html and the FAQs (eg http://www.www-net.com/java/faq/) before resorting to the comp.lang.java.* newsgroups, etc. For other resources, check out Gamelan in USA and the UK's Java Centre. Familiarise yourself with the language by looking at the examples and writing your own simple applications. See the sidebar for some Java pros and cons.

Getting an applet to do anything useful is not quite as simple as it may seem as browser security is so tight. See the sidebar for the range of possible options.

For a new development you will have to decide what technology to use. HelpIndex is based on the original 1.0x Java Development Kit (JDK) from Sun. However that soon will have an improved 1.1 version. Then many suppliers have alternatives, which usually build on top of the JDK, mainly to improve the AWT windowing classes. For example, some may choose Netscape's Internet Foundation Classes as the baseline for new development soon (see its separate review) . See the sidebar for a full discussion of APIs.

However you must ask which people out there will have all these latest classes. Unless Netscape's IFC, for example, is built into all browsers, particularly Microsoft's Internet Explorer (IE3.0), then you will be restricting yourself to Netscape Navigator 4 users. No one will want to download the 500kB classes on-line. For intranet applications you can, of course, ensure that your chosen extension classes are available on all user computers.

You will also have to work out how best to test your new applet. As a minimum I suggest that you that you try it out using IE3.0 and N3.0 browsers at a couple of screen resolutions. Ideally you should try other platforms and earlier browser versions.

Be warned that Java runs s-l-o-w-l-y.

Sidebar

Doing anything useful

Java's security is so strict that you have a job inventing something useful to do - I mean: solving that business problem. Applets cannot read or write local files and can only access the server they came from. You can see why most applet demos are just pretty animations. In future trusted applets may access other servers.

To be useful, you have to write a Java application (which runs outside a browser) or have your applet host do something clever in a CGI or ISAPI program, which could be a server-side Java application. So big projects will inevitably be client-server in nature.

Alternatively you can use a server's databases using JDBC (like ODBC). There are already quite a few ways of accessing databases live over the Internet or Intranet, and I am sure JDBC and other Java APIs will feature in each vendor's armoury of tools.

Then there are some forms of object RPC. Remote Method Invocation (RMI) uses RPC to invoke class methods on servers.

PHD's HelpIndex applet takes another approach to do its relatively simple task. The content developer runs a (Java) program off-line to create some information; the file is then uploaded. The applet can read the file and do some useful work based on its contents.

There is currently no support for printing from Java.

Objects

As a C/C++ person, I am used to tracking allocated memory carefully. All this goes out the window with Java, as you allocate willy-nilly, relying on Java to garbage collect. Let's hope it does it efficiently.

I was fooled a bit at first by object variables. Now I tend to think of them as pointers (technically "references"). For instance, I wanted to make a bit of room around one of my screen components. To do this, I tried to override the insets() method as follows:

public Insets insets()
{
	Insets ri = super.insets();
	ri.left += 5;
	ri.right += 5;
	return ri;
}

The problem is that my ri Insets Object in effect points to the insets in the parent component, so my changes altered the parent's insets. This causes a problem as the insets() routine can be called many times. A better solution is to create your own new Insets instance to return.

public Insets insets()
{
	Insets ri = super.insets();
	return new Insets(ri.top,ri.bottom,ri.left+5,ri.right+5);
}

Sidebar: Java pros and cons

Java Niceness

It is good that characters are 16 bit UNICODE unsigned integers. There is no clumsy mechanism for saying whether you want 8 or 16 bit characters. So, there is just one set of string routines to use. UNICODE forces you to think about how best to write a character out as an 8 bit byte, if that is what you really want to do.

Similarly it is nice to have a boolean basic type. Ditto for 64 bit longs, even though I have not used them yet.

When building a string using the + operator, the compiler nicely converts the basic types and classes to their string representation. Classes are all objects, and an Object has a toString() method which is called in this case. This is handy, so provide a customised toString() for your classes. Similarly provide your own equals() method if appropriate.

While on the subject, also implement getAppletInfo() and getParameterInfo() for your applet.

Thankfully there is no multiple inheritance to cope with. Instead an interface is an abstract interface which a class can opt to implement. Sometimes I like to think of interfaces as call-backs. So if your applet implements Runnable (an interface) then it has to have a run() method. A new thread can be made with your applet passed as a constructor parameter. The thread calls run() to do its work.

Java Clumsiness

Some aspects of Java appear clumsy.

Compilers produce one or more .class output files from a .java source. Java insists that each compiled class or interface exists as a separate output file. This is just plain silly - imagine if the MFC DLLs were distributed in this way. More importantly this has serious speed implications for applets. A browser has to put in a separate request for each class file. Luckily JDK 1.1 introduces Java Archive (JAR) libraries which contain several compressed files of any type which a ClassLoader can get in one fell swoop. In the mean time this cramps our style, as we use various techniques to reduce the number of classes needed for an applet, as described below. JAR file entries are digitally signed to indicate their origin.
Browsers get round this problem by having all their classes in zip files.
Microsoft is separately touting its existing cabinet of files format (CAB) to solve this problem, and has classes available to build and download cabinets.

A constant is usually declared as public static final int CONST = 0 or similar, which is a bit of a mouthful. If you have constants you want to share across projects, you cannot simply include a header file. Constants must be declared in a class, so you must import the class; I presume that the class must be loaded at runtime for these constants to be visible.

In contrast to the automatic conversion to strings mentioned above, String s = i does not work. String s = ""+i does. However you are supposed to use String s = new Integer(i).toString().

If you had not guessed it, the Integer class is an Object wrapper for an integer; there are wrappers for other basic types. The Vector class is an expandable collection of objects. To make a vector of integers, you have to make them into objects, eg use myVector.addElement(new Integer(i)) to add an integer, and ((Integer)myVector.elementAt(n)).intValue() to retrieve it. Of course, you should derive your own IntVector class.

Initialising simple structures is difficult, If you had a colour lookup class:
class ColourLookup { String name; Color colour; }
then it would be nice to initialise an array of instances. However this is not easy. The best you can do is:
Object[][] colours = { { "white". Color.white }, { "red", Color.red }, };
This way you have to cast each element to its appropriate type. Worse, this solution will not cope with basic types unless you wrap them as objects, eg instead of 5 have new Integer(5).

Finally, my early forays indicated that not all Java Virtual Machines were equal, or at least not all Java implementations. Later we shall see that different PC browsers behave in slightly different ways.

Sidebar: APIs

API Primer

A language or operating system is usually seen in terms of the libraries or classes that come as standard. Originally C had printf() and the like. C++ had its streams (which I never used). UNIX had exec(), etc., in 1000+ combinations. PC BIOS had INT 10 to 1F, and DOS INT 21.

Macs' initial success partly came about as third party programmers had to use standard user interface routines. For the same reason, the Window 16 bit API became the standard PC programmers had to know. Now there are a gazillion Windows API you could know, from MFC downwards.

Similarly, the Internet's success must partly be due to its set of standards, many of them quite simple. Now, rival suppliers are trying to outdo each other, not least with acronyms, to provide easy (huh!) ways to lock in, sorry support users and write programs or content.

You could spend you entire programming life keeping up with what is going on, without earning a penny.

Anyway how does Java fare in this minefield? In particular what are the baseline class libraries like?

JDK, etc.

Here are the main JDK API packages:

  • java.lang
  • java.util
  • java.applet
  • java.awt
  • java.net
  • java.io

java.lang has elements which are essentially part of the language, eg the String, Thread and Exception classes. java.util has a few useful additions such as the Vector class.

The java.awt Abstract Window Toolkit (AWT) classes are discussed below.

The java.net network classes implement TCP/IP sockets. With the URL class you can access web sites, but not FTP servers, etc. There are no SMTP or POP3 classes, for example, although I am sure you will find them at Gamelan.

java.io covers files, various sorts of streams and pipes. For Java applications, there no support for serial ports, etc.

The JDK includes a command line compiler and debugger.

The new JDK is trying to catch up on other fronts, eg with digital signing and internationalisation.

Generally, the Java language and the core JDK are still in their youth. They have not settled down, which will hinder Java's adoption, or at least annoy its practitioners. As there is lots of functionality not provided, there is plenty of scope for projects...

java.awt should have been the place to establish a new set of user interface rules. Although its idea of layouts - to cope with different size screens - is good, the rest of the toolkit only just provides enough workable functionality. Now lots of people are trying to do the same job - which Sun should have done in the first place - leaving the developer and user alike in a sea of differing window kits.

Sun's Other APIs

Sun have a list of their current and proposed Java APIs at http://java.sun.com/products/apiOverview.html.

As mentioned before, JDBC provides low-level database access, akin to ODBC. IDL and RMI deal with running objects on other platforms; soon to be supported by a Netscape plug-in.

Interestingly, there is a new concept of 'servlets' which users can upload to run on a server.

Other APIs cover security, secure financial transactions, network management, multi-media players, application data sharing, 2D and 3D objects and telephony.

Java Beans is their contribution to the confusing overcrowded world of software components.

Netscape APIs

Netscape is the main other Java player of interest at the moment. It has a DevEdge developer support program, sold in two species.

Netscape push their own Open Network Environment (ONE) for Java and Javascript, including software development kits. LiveConnect is their way of tying together browser and server objects. Trusted applets may be able to access other hosts and local files. Their servers can already run Java applications. So there is scope for writing server agents that act on a user's behalf.

Netscape's Internet Foundation Classes (IFC) add several areas of functionality. Its windowing system sits on top of java.awt. As reviewed elsewhere, there are more user interface controls, simple animation, drag and drop, timers, multi-font text and a persistent store or object archive system.

Netscape has licensed Visigenic's VisiBroker for Java ORB.

Others

Strangely enough, things have been quite quiet from that notorious API generator, Microsoft (apart from cabinets). Their Visual J++ IDE have classes to talk to COM objects, including DAO controls, and applets can be made into ActiveX objects. As IBM seems to be adopting Java, they are sure to contribute APIs to the language's repertoire.

Using AWT

The JDK Abstract Window Toolkit (AWT) feels limited. It is nowhere near a document and view architecture. It has events and graphics contexts, along with forms and controls.

Despite improvements promised in JDK 1.1, the limitations are such that alternative windowing systems have emerged from other development tool suppliers. These are mostly built on top of AWT. No doubt each one will have its own resource format, eg Java Workshop has a .gui resource file. It is a shame that there cannot be one good system. java.awt will always be there, so it is best to get to know it. So, HelpIndex was based on AWT.

AWT does well to address the problem of each user having a different display. Its classes lay out Components (fields, etc.) in Containers (windows/dialog box forms). You are not supposed to give absolute locations, but tell one of the Layout classes the preferred size and order, and let it get on with the task of laying out the window.

There is some sort of event model, though I have found no event loop. There is no resource format and no printing. There is no tabbing between fields and no default buttons. HelpIndex uses its GridBagForm class to get round these last two problems.

There are standard ways of avoiding flicker in windows. update() makes an off-screen bitmap graphics context for paint() to use. update() then blasts the image onto the screen quickly. HelpIndex does not need to use this technique as it does not normally do any painting; it relies on AWT components which draw themselves, laid out automatically.

Event Handling

There are 30+ events, coming from user interactions with components.

Events are first passed to handleEvent(). Either handle them here and return true, or return super.handleEvent(). If super.handleEvent() is not called then the event is ignored by the actual component, eg the key press is ignored.

super.handleEvent() passes the event to the appropriate delegated applet event handler, then to Component. action() for button presses and menu selections, or one of these appropriately named routines: keyDown() keyUp() mouseEnter() mouseExit() mouseMove() mouseDown() mouseDrag() mouseUp() lostFocus() gotFocus(). You should return false from keyDown(), etc. if you want a component, eg a TextField, to receive the key.

Notice that you can either handle an event in handleEvent() or the appropriate delegated handler, eg keyDown().

I found for key events that the underlying component had not processed the event when you get to look at it. Eg when a key is pressed, if you get the TextField's text in keyDown() then the new character is not there. So to process a key (or succession of keys) HelpIndex gets the processed text in keyUp(), which is slightly naff. You could use keyDown() as a key filter, eg to implement a number only class derived from TextField.

Component Ids

Having received an event, how do you know which object it has come from?

The simplest technique is to have an applet variable for each component you create and see if the event target matches that component. Alternatively, the poor JDK examples actually rely on matching a button's text, eg if text is "OK" then do this. Change the button text and change your code; yuck!

A better technique (methinks) is to have an integer id for each component of your form. HelpIndex's GridBagForm class - see code box - provides this facility wrapped round the GridBagLayout class. GridBagForm.getIdFromComponent() and GridBagForm.getComponentFromId() are used in event handling. GridBagForm also has methods to handle tabbing between components, and to remember the current field when you mouse click to a new tab field.

Obviously you could subclass each component, eg MyButton derived from Button and have an id for each button.

Class reduction techniques

As mentioned above, currently it is advisable to cut down the number of classes that you use in applets - to reduce load time. This definitely goes against the grain, as it tends to make programs less understandable. OO enthusiasts will be turning in their swivel chairs, objecting.

Even a simple structure must be a class. If you want a simple class, it is difficult to initialise, as the ColourLookup example class showed earlier. The messier array-of-objects solution avoids generating a new class.

A new exception means a whole new class, so reuse existing exceptions.

Here is a sneaky way to avoid having an extra class in some situations. Have the static class represent a collection of instances of the class. For instance, I use this technique in GridBagForm where each instance is an individual form component, while the static class is used to manipulate the whole form. Obviously you could only have one such collection class in your program. This technique goes wrong with applets if there are multiple instances of an applet, as the static class will be the same for each applet instance.

Figure 2 shows how GridBagForm has a static Vector called itemList. The elements of this vector are each GridBagForm instances which store information about each component on the form.

Figure 2.

Another trick is to avoid having a class extending Thread. Get another class (eg your applet) to implement Runnable and do your thread stuff in run().

Applet Programming

You have to become familiar with a new programming paradigm. It used to be a cardinal sin to put up any sort of child window, even a message box, since these windows could lock up your computer. Even now it is best to try to work within your given bounds. HelpIndex now has two modes. You can either view its search form set within a page, "applet" mode. Or more usefully, you can have it as an icon initially; when you click the icon, the search form appears in a "floating child window" above the browser.

To make a child window you will need to make a Frame. You need not make it visible if you just want to then make a Dialog. You have to construct dialog boxes by hand. You can either have a class derived from Dialog, or just use Dialog in your frame, and handle all the events in the frame. Dialogs can be modal (with respect to their frame, but not the browser). Only child frame windows can have menu bars, ie applets cannot.

HelpIndex uses its HelpIndexForm class to cope with the two modes. The HelpIndexForm extends the JDK Panel class and contains all the form components. In applet mode, this form is simply added to the applet container. In floating window mode, when the user clicks the icon, a new HelpIndexFrame is first created and then the form is added to it, as shown in figure 3. This approach allows all the user interaction to be handled in HelpIndexForm whether in applet or window mode.

Figure 3.

The following simplified code shows the floating window is created. You can get the preferredSize() for the frame. It is not clear whether the preferred size is supposed to include the borders, but you do need to add something; so add the frame's insets, ie the size of its borders. For IE3.0 you have to do the resize() after the show().

	ourFrame = new HelpIndexFrame(this,FrameTitle);
	ourForm = new HelpIndexForm(this);
	ourFrame.add("Center",ourForm);
	ourFrame.show();
	Dimension frameSize = ourFrame.preferredSize();
	Insets frameInsets = ourFrame.insets();
	ourFrame.resize(frameSize.width+frameInsets.left+frameInsets.right,
					frameSize.height+frameInsets.top+frameInsets.bottom);

If working with your own visible frame, then you will need to derive your own class from Frame, at the very least to catch Event.WINDOW_DESTROY messages. HelpIndex has a small derived class HelpIndexFrame to do this. HelpIndexFrame also sets up the menus in its constructor.

Applets cannot resize themselves or be resized.

If you run an applet twice on the same page (or in different previous pages) then the static classes members are shared betwen the two instances. So be very very careful with you static variables. Note that this clobbers the class reduction technique described above where the static class has a per-applet meaning.

PC Browsers

It is worth while checking that your applet works with both common PC browsers N3.0 amd IE3.0, which do have some significant differences.

If you are developing an applet, then you usually need to stop and restart a browser if you want to test any changes. This is a bit of a bore. Changes in applet parameters generally are not visible without a restart. Setting the disk and memory cache size to zero solves this problem at the expense of performance.

IE3.0's Java implementation seems slightly behind N3.0.

In N3.0, you can set the foreground colour of Label components.

Perhaps more importantly, only N3.0 generates the MOUSE_ENTER, MOUSE_EXIT, GOT_FOCUS and LOST_FOCUS events.

In IE3.0, if you make a Java call to show a web page, where the URL is a local file with an anchor name, then the page is not displayed.

IE3.0 includes a font "ZapfDingbats" which has lots of useful symbols.

How browsers start and stop applets

How do browsers start and stop applets, eg when its page is selected or when the user moves to another page?

First, it needs to be said that applets seem to keep running when the user moves to another page, which is decidedly poor in my opinion. I think they try to keep the input focus if they have it. At the very least, I would have expected that an applet's threads are suspended.

All classes can have static initialisation and finalize() destructor methods. In addition, applets have init(), destroy(), start() and stop() methods.

When first run, an applet's static initialisation is called, a new instance of the Applet is created, init() is called, then start(). Fine.

If you leave the web page then stop() is called. If you then go back then the applet is still there and start() is called. So start() might be the appropriate place to put the input focus in the desired initial place. You might deem it necessary for all initialisation to happen in start().

In N3.0 but not IE3.0, if you reselect a link to the web page (as opposed to just going back to it) then the applet is sort-of-restarted. The static initialisation is not called, but a new Applet is created, init() and start() are called. All the applet's components need to be rebuilt. So be very careful to make sure that your init() handles this case as you would like. To be completely safe, you might want to initialise all your variables and other classes in init().

static initialisation new Applet init() start()
First visit x x x x
Go back x
Second visit (N3.0 only) x x x

destroy() is supposedly only ever when the browser is shut down. I have not confirmed this yet.

Improving the User Interface with Threads

In applets, use threads to speed up the response time for users.

If there is a long task at start-up, then do it in a thread started in init(). Returning from init() lets the applet show itself. Obviously let the user know that some work is in progress.
Make sure you avoid problems that might occur if init() is called more than once, as explained above.

HelpIndex's init() starts another thread to read its help index from the server, which may take several seconds. A status message is displayed until the index has been read. The user can type in the applet's fields, but a lookup does not occur until the index has arrived.

HelpIndex also uses threads to do the lookup task, as this may take a second or so for large indices. The task is carefully designed so that it can be stopped and restarted when another key is pressed. Note that you should use the synchronized keyword to schedule operations. As well as synchronized methods you can have synchronized blocks, locking the class instance, as this simplified example from HelpIndex shows:

private Thread TaskThread = null;
private void DoLookup()
{
	synchronized(this)
	{
		if( TaskThread!=null)
			TaskThread.stop();
		TaskThread = new Thread(this);
		TaskThread.start();
	}
}
public void run()
{
	LookupIndices(QueryField.getText());
	synchronized(this)
	{
		TaskThread = null;
	}
}

HelpIndex's keyUp() routine simply calls DoLookup(). If there is a search in progress, then it is stopped and a fresh one started. The actual search is done in run(), as the applet implements Runnable to do the thread's work.

Conclusion

There is lots to get right in a fully functional Java program. Both the language and its APIs are new.

When your applet is complete, there are various places where you can get it registered to make it easy for others to find. Apart from Gamelan and the Java Centre, JARS rates applets. HelpIndex got in the top 25% for October 1996.

sidebar

Development Environments

Everyone and their dog are writing a Java development environment.

Masochists can just get by with the command line tools provided with the JDK.

Currently, I am one step up, using Symantec Café Lite (sic), on a CD-ROM from one the SunSoft books.

I have looked at Sun's Java Workshop 1.0. This has potential but I found it unusable, mostly for small but important things. It's also slow.
If you use its Visual Java classes (which also wrap java.awt) then there are 450kB of files for users to download over the net; if you have regular users then these should be downloaded onto their CLASSPATH permanently.

I have not tried Microsoft's J++ (why is that ++ there?), Borland's Latté, Symantec Café or Aimtech's Jamba, not to mention IBM's Visual Age for Java, Scientific Computers' BX-Pro or Software Technologies' X-Designer. Iona has an object request broker, Orbix Web 2.0 and Object Design have a lightweight persistent object store PSE Pro.

Author

© 1996 Chris Cant, PHD Computer Consultants Ltd

Chris Cant runs PHD Computer Consultants Ltd. You can try HelpIndex at http://www.phdcc.com/helpindex/index.html.


PHD Home page.