Anatomy of a Java Applet, Part 3
Articles and Tips: article
Senior Research Engineer
Developer Information
01 Mar 1997
Discusses applet parameters, vector class, event handling, image map applets, and an applet's life cycle. Third and final article in a series covering the fundamentals of Java applets.
- Introduction
- Anatomy of a Java Applet Review
- Creating the HTML Document
- Summary
- For Your Information
Introduction
Java applets are becoming a popular and viable method for bringing dynamic solutions to the web. Applets provide an ideal vehicle for delivering intranet/Internet solutions in a web-centric format. Applets embrace and extend the functionality of today's web browsers. They are a executed within a Java-enabled web browser that includes an integrated bytecode interpreter. Applets are embedded within an HTML document via the <APPLET< tag that references the Java applet's compiled .classfile.
This DevNote is the third and final in a series covering the fundamentals of Java applets. This series is intended for developers who are relatively new to Java and Java applet development. The articles should be informative if you're the webmaster/developer type who may have some experience with Visual Basic, Delphi, C, or C++. For those interested in moving into the Java world, this series of articles should help you quickly understand the fundamentals of Java applet development. Knowledge of basic object-oriented terminology is assumed.
Anatomy of a Java Applet Review
In Part 1 we covered the following topics:
Java applets vs. Java applications
The HTML Java applet tag
Applet parameters
Applet life cycle
The java.applet package
A sample "Hello World" Applet.
In Part 2, we expanded on Part 1:
Reasons for writing Java applets
Java RAD tools
The Abstract Window Toolkit (AWT)
Event handling
A sample image map applet
The sample image map applet presented in Part 2 was an applet that allowed for linking from "hot spots" on an image to specified URLs. We spiced it up a bit by creating pop-up balloon help that displayed a description of the designated URL when the mouse pointer entered one of the hot zones. Here is a screen shot of the finished applet from Part 2:
Figure 1: Completed image map applet.
Part 3 builds on the prior concepts and introduces a few new applet fundamentals. Topics covered in this DevNote include:
More on applet parameters
Using the StringTokenizer object to parse delimited text
Using the Vector class
More on event handling
More details on an applet's life cycle
Informational applet methods for completeness
Constructing and new image map applet
Let's start with a discussion of the sample applet's functionality.
Sample Image Map Applet Modified Specification
Many of the features in the Part 2 sample applet were hard-coded, limiting the applet's general usefulness. We concluded that the applet would be improved by using applet parameters in the HTML <APPLET< tag to pass information to the appletCinformation such as the URL for the image to be used for the map, the location and size for n number of invisible buttons, the text for display in the balloon help, and the URLs to be used for each hot spot.
If you examine the code generated for us by our RAD tool in Part 2, notice that the design is tied inextricably to instances of the invisibleButton components used for the hot zones. The code that instantiates, positions, and adds these components to the applet's container is in the init() method. Since we don't know how many hot zones the HTML author will include, this approach will no longer work. The event framework is also dependent and designed around known instances of objects that are guaranteed to exist. Consequently, we must consider a redesign of the entire applet.
This is a good example of why a good design is important before heading down the path of no return. We will reconsider the event handling demonstrating the use of mouseUp()and mouseMove() events. This will actually be less complex than overriding the handleEvent() method and creating our own event framework as we did in Part 2.
Applets are able to communicate with a browser and ask it to do things such as load a new page. This is accomplished with methods found in the interface java.applet.AppletContext. We used the getAppletContext() and showDocument() methods in Part 2 but skimmed over the details. Part 2 used the showDocument() method with the target frame hard-coded to always launch the specified URL in a new instance of the browser. It would expand the applet's usefulness if the HTML author could have more control over the browser.
We add another item to our list of information to be passed in via a parameter for setting the target frameCtext we can pass in as the optional second parameter for the showDocument()method.
The getAppletContext() method returns an object of type AppletContext. Once we have an object reference, we can use the showDocument() method that allows for showing a new web page in the browser. The showDocument() has two forms:
void showDocument(URL url) void showDocument(URL url, String target)
The first form simply replaces the current page with the page specified in the URL parameter. The second form takes a second argument, a target string that can be used to specify the target frame in which to display the target URL. Valid target string values include:
Target String
|
Description
|
"_self" |
Show document in current frame. |
"_parent" |
Show in parent frame. |
"_blank" |
Show in the topmost frame. |
"_top" |
Show in a new instance of a frame |
If and how various browsers support these features should be tested. The HTML author can now decide whether the hot link will open a new instance of the browser, or simply have the browser display the page in the same browser. The sample applet needs to accept two type of parameters: 1) a relative URL with path and file name of the image file to used for the map, and 2) hot-zone information for each invisible button. The hot zone parameter values will be passed in via a comma-separated list formatted as "x, y, width, height, help text, target frame, URL." Java's coordinate system has its origin (0,0) in the upper left corner; all measurements are done in pixels.
Figure 2:The Java graphics coordinate system.
Since the applet needs to accept any number of hot spots in any location, objects must be created dynamically at run time. We specify that the applet will dynamically create objects based on the input parameters since this information is unknown at development time. The applet will provide pop-up balloon help, similar to what was done in Part 2, using a java.awt.textField component. We also use a java.awt.TextField component to display some status information at the bottom of the screen for debugging purposes. With the basic description of the applet in place, as the first step in building the applet, let's cover the required changes to our HTML document.
Creating the HTML Document
Recall that applet parameters can be specified with the use of the optional <PARAM< tag--part of the <APPLET< tag in the HTML file containing the applet. The <PARAM< tag has two parts--a name and value. A single image is to be used for the map, so we pass the relative URL in a single parameter named "mapimage". The value, a relative URL, will include the path to the file and the file name. The actual contents for name and value are placed inside double quotes and are assigned as follows: <PARAM name=<mapimage< value="images/spacewld.jpg"". Since values are passed in as a single string, delimited text can be used to pass in mulitple values. As we discussed, each button will need the x, y, width, height, help text, target frame, and URL for each hot zone. To support any number of hot zones, we decide on a naming convention for the hot zone parameter names that follows the sequence, "button1," "button2," "button3," ... "button n." A sample HTML document with eight hot zones defined now look like this:
<HTML<< <HEAD<< <TITLE<Novell Research Command Center</TITLE<< </HEAD<< <BODY<< <APPLET CODE="ImageMap.class" WIDTH=640 HEIGHT=495<< <PARAM name="mapimage"value="images/spacewld.gif"<< <PARAM name="button1" value="276,288,93,96,About Novell Research,_self,about.htm"<< <PARAM name="button2" value="36,108,87,111,Novell Research Library,_self,anthology.htm"<< <PARAM name="button3" value="156,96,84,84,Network Games Demos,_self,nrgames.htm"<< <PARAM name="button4" value="264,108,120,120,Research Web Picks,_self,nrwebpicks.htm"<< <PARAM name="button5" value="408,108,84,84,Topical Search,_blank,topical.htm"<< <PARAM name="button6" value="516,108,96,108,Interactive Education,_self,devedu.htm"<< <PARAM name="button7" value="432,216,78,88,Robo Full Text Search,_self,ftr.htm"<< <PARAM name="button8" value="468,360,72,48,Cool Tools,_self,cooltool.htm"<< This is the place for alternative HTML. Browsers that don't support applets will display this section instead of running the applet. Since this is an ImageMap applet, this would be a good place for HTML that links to the same URLs that are specified in the applet parameters. </APPLET<< </BODY<< </HTML<<
The Applet Life Cycle
Recall that the system will call certain methods during the life cycle of an applet. These methods include: init(), start(), stop(), destroy(), and paint(). Our sample applet will override most of these methods and introduce the update()method in order to accomplish the tasks specified.
The init(), paint(), and update() Methods. We decide to use one of the Java base classes, java.awt.Image, as the class to handle the background map image. Use of this class will leverage the caching features of the browser. The code fragment reads the "mapimage" parameter and loads the specified image into the Imageobject like this:
//gets an image relative to a URL //name of image file to be used for map... String ImageFile = getParameter("mapimage"); image = this.getImage(this.getDocumentBase(), ImageFile);
We want the image to be redrawn every time the browser window is activated, so we override the paint() method and include code to draw the image. The complete code for the paint() method looks like this:
public void paint(Graphics g) { //draw image passed in from HTML parameter stored in class variable g.drawImage(image,0,0,this); }
It's worth noting that the AWT actually calls the update() method when a window needs to redraw itself. The default action of update() is to erase the screen and then redraw it. This can result in flicker in some situations since update() may be called multiple times while loading an image. We can create an easy fix by overriding the update() method and by adding a direct call to the paint() method. Here is a look at the code fragment:
public void update(Graphics g) { paint(g); }
The start() and destroy() Methods. The start() method is called by the system at startup after the init() method is called and then again each time the browser returns to the web page containing the applet. After a user clicks in a hot zone taking them to another URL with the same browser, the balloon help will still be visible when they return to the page containing the applet. Therefore, we add code to hide the textField and empty its text when start()is called.
public void start() { //override this method so we can clear the balloon help text... //otherwise it will be visible when a user uses the browser's back feature //after linking to another page... textFieldBalloonHelp.hide(); textFieldBalloonHelp.setText(""); }
The destroy() method is called once by the system when the applet shuts down normally; therefore, it's a good place for code that frees up system resources. The java.awt.Image class includes a method flush()for freeing all resources being used by an Image object including any pixel data that is being cached for rendering to the screen as well as any system resources that are being used to store data or pixels for the image. Here is the code for our destroy()method.
public void destroy() { //called by the system when applet is shutting down normally image.flush(); }
We will return to the applet's life cycle later in the DevNote with some event handling methods, but first we need to create some other code leveraging the AWT to store the hot zone information. We do this with a helper class; instances of the class will be used to keep track of hot zones.
A Helper Class for Hot Zones
A good solution for replacing the components we used in Part 2 is to create our own object that meets our needs by inheriting from one of the AWT shape classesCjava.awt.Rectangle. Rectangle instances will be created based on the parameters passed in from the HTML document. The graphics classes have some useful methods such as inside()that can used to establish whether a (x, y) location is anywhere inside the shape. Let's look at the new class we call ImagemapRectangle. Notice that we have added the helptext, target, and url members. We will use these to keep track of the text we want displayed in the balloon help, the target frameCwhere to display the specified URLCand finally, the URL of the page to load when the user clicks in a hot zone. Here is the class definition:
class ImagemapRectangle extends java.awt.Rectangle{ String helptext; String target; URL url; public ImagemapRectangle(int x, int y, int w, int h, String helptext, String target, URL url){ super(x,y,w,h); this.helptext = helptext; this.target = target; this.url = url; } }
ImagemapRectangle instances must be managed. The list will need to grow based on the number of invisible buttons specified in the HTML document. The list will also need to be easily traversed to determine whether the pointer is inside any of the hot zones.
Using the Vector and StringTokenizer Classes
Java provides a great class, the Vector class, for handling a set of objects when you don't know up front how many objects you will have. The class implements a dynamic array of objects that can grow and shrink as needed. We use an instance of the Vector class in our applet to hold references to instances of our ImagemapRectangle objects. We use the addElement() method to populate the array in our applet's init() method. The following code fragment shows how to load the array with instances of our ImagemapRectangleclass.
hotzones = new Vector(); //load Vector object array with shapes i = 1; while((r = getRectangleParameter("button" + i)) != null){ hotzones.addElement(r); i++; }
The getRectangleParameter() is a method we add to our applet class that returns an instance of an ImagemapRectangle object or null depending on the existence of appropriately named parameters in the HTML file. For each hot zone, an object is added to the array with the addElement() method. Here is the code for the getRectangleParameter()method:
protected ImagemapRectangle getRectangleParameter(String name) { int x,y,w,h; String helptext, target; URL url; String parval = this.getParameter(name); if (parval == null) return null; try { StringTokenizer str = new StringTokenizer(parval, ","); x = Integer.parseInt(str.nextToken()); y = Integer.parseInt(str.nextToken()); w = Integer.parseInt(str.nextToken()); h = Integer.parseInt(str.nextToken()); helptext = str.nextToken(); target = str.nextToken(); url = new URL(this.getDocumentBase(),str.nextToken()); } catch (NoSuchElementException e) { return null; } catch (MalformedURLException e) { return null; } return new ImagemapRectangle(x,y,w,h,helptext,target,url); }
The method uses the now familiar getParameter() method to get the delimited list that defines each hot zone passed in as a parameter. A StringTokenizer object is used to parse the list. The java.util.String.Tokenizer class is designed for this type of use. An instance of the class can be created that attaches to a string. The nextToken() method can be used to parse delimited list with relative ease. The above code loads a string and attaches it to a new StringTokenizer object. Then it moves through the string with the nextToken() method parsing the list and assigning tokens to variables. Once the string is parsed, a new ImagemapRectangle instance is created and returned if the parameter exists; otherwise, our method returns null. We assume for our applet that the number of items in the comma separated list is always the same. If you can't make this assumption, you can use the hasMoreTokens() method which returns true if more elements exist. The applet now reads in the parameters, loads the image for the background, and populates the Vector array with instances of ImageapRectangle objectsCone for each hot zone. The next step is to handle the mouse or pointer events.
Capturing Events--mouseUp() and MouseMove()
Only two events we need to considered in order to accomplish our goals. As the pointer moves over the applet, we can check to see of the pointer is inside one of the hot zones. We can do this by traversing the array of hot zones stored in the Vector array when mouse moves across the screen. The code to change to a specified URL will also perform the same check whenever the user clicks the mouse. Since both mouseUp() and mouseMove() will require traversing the Vector array, we create a method that can be used by both event handlers. We design the method to return a reference to the ImagemapRectangle object containing the location. If the mouse is not inside one of the hot zones, the method will return null. We call the method findrect(); here is the code:
private ImagemapRectangle findrect(int x, int y) { int i; ImagemapRectangle r = null; //hotzones.size() is the number of shapes in the Vector array //for each hotzones see if x,y are inside break with r referencing //shape x,y are inside... for(i=0;i < hotzones.size(); i++) { r = (ImagemapRectangle)hotzones.elementAt(i); if(r.inside(x,y)) break; } //return r if inside shape, else return null if (i < hotzones.size()) return r; else return null; } }
The balloon help needs to be visible when the user moves the pointer into a hot zone and invisible when the pointer moves out of a hot zone. We call the findrect() method from the mouseMove() event handling method to do this. If the mouse is inside a hot zone, the help is displayed in a appropriate location. As the mouse moves out of a hot zone, the component is hidden and the text is cleared. In the mouseUp() method, findrect() is also used to see of the pointer location is inside the hot zone. If so, the appropriate URL is loaded. Here is the code for the mouseMove() and mouseUp() methods.
public boolean mouseMove(Event e, int x, int y) { //show or hide balloon help depending on mouse location... ImagemapRectangle r = findrect(x,y); //if inside a hotzone... if (r != null) { //set the text for TextField used as balloon help... //magic number of 500 used for images typically 640 pixels wide if (x < 500) textFieldBalloonHelp.reshape(e.x + 10,e.y + 10,125,24); else textFieldBalloonHelp.reshape(e.x 100 ,e.y + 10,125,24); textFieldBalloonHelp.setText(r.helptext); textFieldBalloonHelp.show(); textFieldtestout.setText("In " + r.helptext + " zone loads " + r.url); } else { // Hide, empty, and move the textField used as balloon help... textFieldBalloonHelp.hide(); textFieldBalloonHelp.setText(""); textFieldBalloonHelp.reshape(0,0,125,24); textFieldtestout.setText("Outside all hot zones at (x,y): " + x + "," + y); } return true; } public boolean mouseUp(Event e, int x, int y) { //find out if user is in hot zone... ImagemapRectangle r = findrect(x,y); //if r references hot zone r is not null if (r != null) { // link to the specified URL... AppletContext context = getAppletContext(); context.showDocument(r.url, r.target); } return true; }
To finish up the sample applet, we add two methods used by convention for storing information about the applet such as the author, version, parameter information, etc. The methods are getAppletInfo() and getParameterInfo().
Informational Methods--getAppletInfo() and getParameterInfo()
These methods exist for the purpose of providing textual information to users. Professionally written applets should include these methods for completeness. Most browsers will provide some way of examining the information returned in these methods. The getAppletInfo() method is typically used to provide information such as author, version, copyright, etc. Here is an example from our applet:
public String getAppletInfo() { //return a string describing the applet suitable for display in a browser dialog... return "ImageMap v.0.4 written by Steven C. Jones, Sr. Research Engineer, Novell Developer Information."; }
The getParametInfo() method should return an array of array of strings that describe each parameter name, type, and description. Here is the method for our sample applet that describes valid parameters.
public String[][] getParameterInfo() { //array of array of strings describing each valid parameter... //includes: parameter name, parameter type, parameter description... String[][]paraminfo={ {"mapimage", "image file name", "relative URL to image file: path and file name."}, {"button#", "x, y, width, height, balloon text, target frame, URL link", "hot zone specifications."} }; return paraminfo; }
Here is a screen shot of a browser running our applet displaying this information. Figure 3:Browser Showing Applet Information Returned by getAppletInfo() and getParameterInfo()Methods.
Our sample applet is now complete. It's a little redundant, but since we didn't cover all the code for the applet and in order to provide some context and the completed applet, we include the full source for the applet:
Full Source Code Listing
/* An ImageMap applet a basic extension of the java.applet.Applet class. The applet reads parameters in the HTML applet tag that specify the URL for an image to be used as the map and that specify the "hot zones" or invisible button information. These hot zones also provide "balloon help" that is displayed when the user places the pointing device within a hot zone. When the user clicks in a zone, the specified URL is loaded. */ import java.awt.*; import java.applet.*; import java.net.*; import java.util.*; public class ImageMap extends Applet { protected Vector hotzones; protected Image image; public String[][] getParameterInfo() { //array of array of strings describing each valid parameter... //includes: parameter name, parameter type, parameter description... String[][]paraminfo={ {"mapimage", "image file name", "relative URL to image file: path and file name."}, {"button#", "x, y, width, height, Balloon text, target frame, URL link", "hot zone specifications."} }; return paraminfo; } public String getAppletInfo() { //return a string describing the applet suitable for display in a browser dialog... return "ImageMap v.0.4 written by Steven C. Jones, Sr. Research Engineer, Novell Developer Information."; } public void start() { //override this method so we can clear the balloon help text... //otherwise it will be visible when a user uses the browser's back feature //after linking to another page... textFieldBalloonHelp.hide(); textFieldBalloonHelp.setText(""); } public void destroy() { //called by the system when applet is shutting down normally image.flush(); } public void update(Graphics g) { //called in response to a call to repaint... //background is not cleared reducing flicker... paint(g); } public void paint(Graphics g) { //draw image passed in from HTML parameter stored in class variable g.drawImage(image,0,0,this); } private ImagemapRectangle findrect(int x, int y) { int i; ImagemapRectangle r = null; //hotzones.size() is the number of shapes in the Vector array //for each hotzones see if x,y are inside break with r referencing //shape x,y are inside... for(i=0;i < hotzones.size(); i++) { r = (ImagemapRectangle)hotzones.elementAt(i); if(r.inside(x,y)) break; } //return r if inside shape, else return null if (i < hotzones.size()) return r; else return null; } protected ImagemapRectangle getRectangleParameter(String name) { int x,y,w,h; String helptext, target; URL url; String parval = this.getParameter(name); if (parval == null) return null; try { StringTokenizer str = new StringTokenizer(parval, ","); x = Integer.parseInt(str.nextToken()); y = Integer.parseInt(str.nextToken()); w = Integer.parseInt(str.nextToken()); h = Integer.parseInt(str.nextToken()); helptext = str.nextToken(); target = str.nextToken(); url = new URL(this.getDocumentBase(),str.nextToken()); } catch (NoSuchElementException e) { return null; } catch (MalformedURLException e) { return null; } return new ImagemapRectangle(x,y,w,h,helptext,target,url); } public boolean mouseMove(Event e, int x, int y) { //show or hide balloon help depending on mouse location... ImagemapRectangle r = findrect(x,y); //if inside a hotzone... if (r != null) { //set the text for TextField used as balloon help... //magic number of 500 used for images typically 640 pixels wide if (x < 500) textFieldBalloonHelp.reshape(e.x + 10,e.y + 10,125,24); else textFieldBalloonHelp.reshape(e.x 100 ,e.y + 10,125,24); textFieldBalloonHelp.setText(r.helptext); textFieldBalloonHelp.show(); textFieldtestout.setText("In " + r.helptext + " zone loads " + r.url); } else { // Hide, empty, and move the textField used as balloon help... textFieldBalloonHelp.hide(); textFieldBalloonHelp.setText(""); textFieldBalloonHelp.reshape(0,0,125,24); textFieldtestout.setText("Outside all hot zones at (x,y): " + x + "," + y); } return true; } public boolean mouseUp(Event e, int x, int y) { //find out if user is in hot zone... ImagemapRectangle r = findrect(x,y); //if r references hot zone r is not null if (r != null) { // link to the specified URL... AppletContext context = getAppletContext(); context.showDocument(r.url, r.target); } return true; } public void init() { super.init(); int i = 0; ImagemapRectangle r; //gets an image relative to a URL //name of image file to be used for map... String ImageFile = getParameter("mapimage"); image = this.getImage(this.getDocumentBase(), ImageFile); hotzones = new Vector(); //{{INIT_CONTROLS setLayout(null); addNotify(); resize(640,499); textFieldBalloonHelp = new java.awt.TextField(); textFieldBalloonHelp.hide(); textFieldBalloonHelp.reshape(0,0,125,24); add(textFieldBalloonHelp); textFieldtestout = new java.awt.TextField(); textFieldtestout.reshape(0,468,640,27); add(textFieldtestout); //}} //load Vector object array with shapes i = 1; while((r = getRectangleParameter("button" + i)) != null){ hotzones.addElement(r); i++; } } //{{DECLARE_CONTROLS java.awt.TextField textFieldBalloonHelp; java.awt.TextField textFieldtestout; //}} }
Image Map Applet Usage
The image map applet can be used to launch other pages that contain the same applet with a different set of parameters. This allows for visual navigation among topics in any number of ways. You can use hierarchical and linear topical arrangements or combinations of the two. Here is a series of screen shots demonstrating how multiple image map applets can be used together. The first image map is the same Command Center we used in Part 2. Figure 4:Main Command Center.
When the user clicks in the Topcial Search area inside the Command Center, a new instance of the browser is loaded with a document containing another image map applet. This image map provides a set of general categories. Figure 5:First Level of Hierarchical Visual Navigation--General Categories
Once there, the user can drill in on subsets of the general category selected. The subset URLs are loaded in the same instance of the browser. Figure 6:Second Level of Hierarchical Organization--Subset of General Category.
When the user clicks on one of subset client topics, an HTML document that contains references to only those documents is displayed. Or, the user can go back to the general categories in the same browser by clicking in the appropriate location. This creates a virtual world metaphor by combining the applets and content together in appropriate ways. This serves as just one example of how multiple documents that contain image maps can be linked.
Summary
Although we have made the image applet considerably more useful, room for improvement still exists. We minimized the flicker produced when drawing the image; however, buffering the image off screen would be a cleaner solution. If you are interested in improving on this code, explore the ImageObserver interface--specifically the imageUpdate() method. The imageUpdate() method is a call-back method that actually calls the update() method. Synchronizing threads may also enhance the performance of the sample applet. A couple of other enhancement details could add some finishing touches. The text field used for balloon help doesn't resize based on its contents. We also used a magic number of 500 pixels to keep the balloon help from painting off the applet's container when hot zones are too close to the right edge. If the images used in the map are not around 640 pixels wide, the "duck tape" fix for keeping the balloon help visible doesn't work. Solutions for these items shouldn't prove difficult for those of you interested in making use of the code. The intent of the Anatomy of a Java Applet DevNote series was to help you get familiar with the fundamentals of Java applet development. The series was intended to provide practical understanding of crucial applet development topics including:
The HTML Java applet tag
Applet parameters
Applet life cycle
The java.applet package
The Abstract Window Toolkit (AWT)
Event handling
Knowledge of these concepts is a critical step in becoming an efficient Java developer. Look for future DevNotes on Java and Java applets that extend this discussion. If you would like to comment directly on this article or hear more on a particular Java subject, E-mail me at scjones@novell.com.
For More Information
If you are looking for the latest information related to Java and the web, please refer to the following Novell developer resources: "Exploring the NetWare Web Server," Novell Application Notes, Feb. 1996. "Exploring the NetWare Web Server-Part 2," Novell Application Notes, Mar. 1996. "Exploring the NetWare Web Server-Part 3," Novell Application Notes, Sep. 1996. "Introduction to the Java Infrastructure for NetWare," Novell Developer Notes, June, 1996. "NetWare SDK for the Java Platform," Novell Developer Notes, June, 1996. "Java on NetWare Takes Shape," Novell Developer Notes, Jul. 1996. "Anatomy of a Java Applet-Part 1," Novell Developer Notes, Aug. 1996. "The Java Development Kit for NetWare," Novell Developer Notes, Nov. 1996. "Anatomy of a Java Applet-Part 2," Novell Developer Notes, Feb. 1997. Novell Research web site at URL http://www.novell.com/reserach/ Novell IntranetWare SDK for Java Download page http://developer.novell.com/net2000/java/ Novell's DeveloperNet web site at URL: http://developer.novell.com/ Novell's Java web site at the URL: http://java.novell.com/ Sun's Java web site at http://java.sun.com/
* Originally published in Novell AppNotes
Disclaimer
The origin of this information may be internal or external to Novell. While Novell makes all reasonable efforts to verify this information, Novell does not make explicit or implied claims to its validity.