Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Tools of the trade, Part 3

Install your Java programs with InstallAnywhere

  • Print
  • Feedback

Page 2 of 6

Note
Check out Resources to obtain either a free copy of InstallAnywhere 5 Now! or an evaluation copy of another edition. The evaluation copies let you create installers that work for three days only.


Core concepts

To effectively use InstallAnywhere, you should understand the InstallAnywhere user guide's core concepts before interacting with the tool:

  • Actions: are custom operations you tell the installer to perform when it runs. Examples: expand an archive, execute custom code, create a folder or shortcut. Some actions describe panels—installer windows—that the installer displays and with which a user interacts.
  • Components: are an installer's smallest units and group files and actions. Components help developers create features.
  • Executable installers: are platform-specific executable files (like Windows EXEs) that install Java and non-Java applications. A Java application consists of classfiles and a program created by InstallAnywhere's LaunchAnywhere technology that loads a virtual machine and the classfile with the byte code equivalent of a public static void main(String [] args) method. A virtual machine may also be included, which the installer and LaunchAnywhere-created program will use. If not included, the installer searches the platform during installation for an appropriate virtual machine. InstallAnywhere creates executable installers for Windows 95, 98, Me, NT, 2000, and XP, and Solaris, Linux, HP-UX, AIX, Mac OS, and Mac OS X.
  • Features: logically group components. Examples include a help feature consisting of help files, registry changes, and so on, and a main feature consisting of an application's essential files. Features help developers create install sets.
  • Install sets: group features that serve as complete installations. Examples include a minimal install set that consists of only those files needed to run an application, a typical install set that consists of the minimal set of files plus help files, and a complete install set consisting of all files. Install sets let users decide which collection of features to install (based on available disk space or other criteria).
  • JAR-based installers: are platform-independent jar files that install Java and non-Java applications. If a platform supports Java, run the installer on that platform by using the java command with the jar file. Create JAR-based installers for those platforms (such as OS/2, Windows NT for Alpha, VMS (Virtual Memory System), and MVS (Multiple Virtual Storage)) that have no InstallAnywhere executable installer support.
  • Magic Folders: are platform-independent folder locations. For example, $USER_INSTALL_DIR$ represents the folder the user selects as the installation folder when an installer runs.
  • Project files: are XML-based .iap_xml files that record project-specific settings, such as a list of filenames for all files to be installed. For example, Lines.iap_xml identifies the project file for a Lines installer project. InstallAnywhere creates a folder for each project and places the project file in that folder.
  • Project Wizard and Advanced Designer: are InstallAnywhere's two modes of operation. Project Wizard, which is the default mode at startup, builds simple installers for multiple platforms. In contrast, Advanced Designer builds sophisticated installers that execute custom code, display license agreements, install to multiple locations on a platform, and so on. Neither mode is exclusive. For example, use Project Wizard to start a project, switch to Advanced Designer to add additional features, and, if desired, switch back to Project Wizard. Specify actions, components, features, and install sets in Advanced Designer only.
  • Rules: are true/false statements that direct the execution of platform-specific actions. For example, use a rule to tell the installer to modify only the Windows 2000 registry and leave other Windows registries alone. These statements also direct the execution of platform-independent actions. For example, use a rule to have the installer display messages in the user's specified language.


Note
InstallAnywhere supports these additional core concepts: API, variables, SpeedFolder, installer localization, silent mode, and console mode. Consult the InstallAnywhere user guide to learn more about those concepts.


A Lines application

"Tools of the Trade, Part 1" introduced you to the Lines applet. Although I would like us to create installers for that applet, we cannot because InstallAnywhere supports the creation of installers for Java applications but not Java applets. We need a way to transform that applet to an equivalent application. One way to accomplish that task exists in my first Java 101 column, "Applications, Applets, and Hybrids." In that article, I introduced you to the hybrid (part applet and part application) program category. By using that article's Hybrid source code as a template, I transformed Lines the applet into Lines the hybrid, as Lines.java's source code shows:

Lines.java

// Lines.java
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
public class Lines extends Applet implements Runnable
{
   static Lines l;
   static Stub s;
   private int width = 0, height = 0;
   private Thread runner = null;
   private final static int MAXCOLORS = 256;
   private final static int SLEEPMILLIS = 50;
   public void init ()
   {
      // Acquire the applet's width and height.
      width = getSize ().width;
      height = getSize ().height;
   }
   public void start ()
   {
      // If no thread exists, create a Thread object that associates with the
      // current Lines object, and start a new thread that invokes the current
      // Lines object's run() method.
      if (runner == null)
      {
          runner = new Thread (this);
          runner.start ();
      }
   }
   public void paint (Graphics g)
   {
      // Generate a random color and establish that color as the Graphics
      // context's drawing color.
      Color c = new Color (rnd (MAXCOLORS), rnd (MAXCOLORS), rnd (MAXCOLORS));
      g.setColor (c);
      // Generate a random set of coordinates in the upper-left quadrant of
      // the drawing surface, and use those coordinates as the starting
      // coordinates for a new line.
      int x1 = rnd (width / 2);
      int y1 = rnd (height / 2);
      // Compute the line's ending coordinates by mirroring the starting
      // coordinates in the lower-right quadrant.
      int x2 = width - x1;
      int y2 = height - y1;
      // Draw the line.
      g.drawLine (x1, y1, x2, y2);
      // Draw an inverse of the line (for symmetry).
      g.drawLine (x1, y2, x2, y1);
   }
   static int rnd (int limit)
   {
      // Return a random integer that ranges from 0 through limit-1.
      return (int) (Math.random () * limit);
   }
   public void run ()
   {
      // Obtain a reference to the thread that was started in the applet's
      // start() method.
      Thread current = Thread.currentThread ();
      // As long as runner contains the same reference, keep looping. The
      // reference in runner becomes null when the applet's stop() method
      // executes.
      while (current == runner)
      {
         // Invoke the paint(Graphics g) method to draw another
         // randomly colored and randomly positioned line.
         repaint ();
         // Pause for SLEEPMILLIS milliseconds to achieve an eye-pleasing
         // display.
         try
         {
             Thread.sleep (SLEEPMILLIS);
         }
         catch (InterruptedException e)
         {
             System.err.println ("Thread was interrupted.");
         }
      }
   }
   public void stop ()
   {
      // Tell the line-drawing thread to terminate.
      runner = null;
   }
   // The following method is overridden to prevent the drawing surface from
   // being automatically cleared after a line is drawn. Stay tuned to Java
   // 101 to learn more about this method.
   public void update (Graphics g)
   {
      paint (g);
   }
   public static void main (String [] args)
   {
      Frame frame = new Frame ("Lines as an Application");
      l = new Lines ();
      // NOTE:
      //
      // It is not necessary to specify frame.add (new Panel ().add (l));.
      frame.add (l);
      // Create the frame's peer. Peer is not visible. This is necessary
      // for when a background buffer must be created in the init() method
      // (e.g., Image bk = createImage (100, 100);).
      frame.addNotify ();
      l.setStub (s = new Stub (args));
      frame.setSize (300, 300);
      frame.setVisible (true);
      // NOTES:
      //
      // 1) l.init (); must follow frame.setVisible (true); or graphics
      //    do not display.
      //
      // 2) The l.doLayout (); call is included in case GUI components
      //    will be added to applet's panel -- because frame window has
      //    already been laid out.
      l.init ();
      l.doLayout ();
      s.setActive (true);
      l.start ();
      frame.addWindowListener (new WindowAdapter ()
                               {
                                   public void windowClosing
                                                       (WindowEvent w)
                                   {
                                      s.setActive (false);
                                      l.stop ();
                                      l.destroy ();
                                      System.exit (0);
                                   }
                               });
   }
}
/* The Stub class provides a mechanism for obtaining information from
   the runtime environment.  Typically, this environment is maintained
   by a Web browser.  For this program, a Web browser environment is
   being simulated. */
class Stub implements AppletStub
{
   private boolean active = false;
   private Hashtable ht = new Hashtable ();
   private Context c;
   // Create a new Stub object.  The application's array of command
   // arguments are passed to this constructor, where they are saved
   // in a Hashtable object for later retrieval by the getParameter()
   // method.
   Stub (String [] args)
   {
      c = new Context (); // Create an applet context.
      // Make sure an even number of arguments has been passed.
      if ((args.length & 1) != 0)
          return;
      for (int i = 0; i < args.length; i += 2)
           ht.put (args [i], args [i + 1]);
   }
   // Return the current state of an applet.  During initialization,
   // the applet is not active (and this method returns false).  The
   // applet's active state is set to true just before the start
   // method is called.
   public boolean isActive ()
   {
      return active;
   }
   // Return the complete URL of the HTML document containing the
   // applet.  This URL includes the name of the document's file.
   public URL getDocumentBase ()
   {
      URL u = null;
      try
      {
          u = new URL ("file:///" + (new File ("").getAbsolutePath ()) +
                       "/x.html"); // Use a fake document.
      }
      catch (MalformedURLException e) {}
      return u;
   }
   // Return the complete URL of the applet's .class file(s).  This
   // method is often used with the getImage and getAudioClip
   // methods to load image/audio files relative to the .class files.
   public URL getCodeBase ()
   {
      URL u = null;
      try
      {
          u = new URL ("file:///" + new File ("").getAbsolutePath () + "/");
      }
      catch (MalformedURLException e) {}
      return u;
   }
   // Return the value of the applet parameter, identified by the
   // name argument.  If not present, null is returned.  The Applet
   // class contains a getParameter() method that calls this method.
   public String getParameter (String name)
   {
      return (String) ht.get (name);
   }
   // Return a reference to the applet's context.  The Applet class
   // contains a getAppletContext() method that calls this method.
   public AppletContext getAppletContext ()
   {
      return c; // Return current applet context.
   }
   // Resize the applet.  The Applet class contains a pair of resize
   // methods that call this method. Note: Web browsers like Netscape 
   // don't allow applets to be resized. 
   public void appletResize (int width, int height)
   {
   }
   // The following method is an extra method that is called to set
   // the value of the private active variable.
   public void setActive (boolean active)
   {
      this.active = active;
   }
}
/* The Context class provides a mechanism to control the environment
   in which the program is running.  Typically, this environment is
   maintained by a Web browser.  For this program, a Web browser
   environment is being simulated. */
class Context implements AppletContext
{
   // Load the file located by the url argument.  The Applet
   // class contains a pair of getAudioClip() methods that call
   // this method.
   public AudioClip getAudioClip (URL url)
   {
      return Applet.newAudioClip (url);
   }
   // Prepare to load the image located by the url argument.  The
   // image is loaded when needed (by one of Graphics' drawImage()
   // methods).  The Applet class contains a pair of getImage()
   // methods that call this method.
   public Image getImage (URL url)
   {
      Toolkit tk = Toolkit.getDefaultToolkit ();
      return tk.getImage (url);
   }
   // Fetch the Applet (identified by name) from the current HTML
   // document.
   public Applet getApplet (String name)
   {
      return null;
   }
   // Return an enumeration to all Applets located on the current HTML
   // page.
   public Enumeration getApplets ()
   {
      return null;
   }
   // Show the HTML document, located by the url argument, in the
   // current Web browser window.
   public void showDocument (URL url)
   {
      System.out.println ("Showing document " + url);
   }
   // Show the HTML document, located by the url argument, in the
   // Web browser window, identified by the frame argument.
   public void showDocument (URL url, String frame)
   {
      try
      {
         showDocument (new URL (url.toString () + frame));
      }
      catch (MalformedURLException e) {}
   }
   // Show a status message, identified by the message argument, in
   // the Web browser's status bar.  The Applet class contains a
   // showStatus() method that calls this method.
   public void showStatus (String message)
   {
      System.out.println (message);
   }
   // The following three methods are required by SDK 1.4.  To learn
   // about those methods, please refer to the SDK 1.4 documentation.
   public InputStream getStream (String key)
   {
      return null;
   }
   public Iterator getStreamKeys ()
   {
      return null;
   }
   public void setStream (String key, InputStream stream)
   {
   }
}


I won't bother exploring Lines.java's source code because of the extensive comments. Furthermore, I explore concepts such as streams in future articles. Compile that source code and run the resulting Lines.class classfile from a command line (via java Lines). Expect to see output similar to what you saw earlier in this series.

  • Print
  • Feedback

Resources