HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

By all accounts, 1996 was the year of Java. In that short year, Java made the transition from a humble, almost academic, cross-platform computing paradigm to becoming the virtual center of the Internet development world. The introduction of applets has helped drive the move from static Web pages to dynamic client-side processing.

Java's explosion onto the scene is not over yet. Today, servlets promise to do for the server side what applets have done for the client side. Furthermore, standalone Java-based applications will soon become the norm. Companies like Sun, IBM and Asymetrix are developing Java compilers that can generate platform-specific machine code from Java source. The face of Java is continuing to change rapidly. This fast-paced environment makes it difficult for most people to comprehend, much less formulate a response.

Java's fast-paced development continues to raise new questions. Is Java better suited for client-side or server-side applications? What is meant by a thin client vs. a thick client? If you use Java on the server side, are you limited to servlets? What are the benefits of using servlets? Are there other options? Are those who are not involved in Internet development precluded from using Java? Finally, what will be Java's future impact in the enterprise client/server development arena and how can I better prepare myself for its arrival?

In this article, I will examine and quantify how Java is being used throughout the enterprise. This examination will not limit itself to the Internet arena. Aside from reviewing how it is being used now, I will discuss how it is likely to be used in the near future (six months, one year, three years). Finally, I will give you concrete examples of how you can start to use Java now, in preparation for the future. I will do this by discussing Java applets, servlets, Java-CGI and standalone applications.

Java Generalities
Before we get into the specifics of the various types of Java programs, let's first discuss what all Java programs have in common.

In general, all Java programs are compiled into CLASS files. CLASS files consist of platform-independent bytecodes. To compile a Java program you need a Java compiler. The compiler, javac, reads the contents of an ASCII Java program file and creates a CLASS file for every class definition (with the notable exception of implicit classes).

To execute the contents of a CLASS file, you must use a Java bytecode interpreter. This interpreter is named java, but is also referred to as the Java Virtual Machine (JVM), Java VM or simply the VM. The Java VM is the platform-specific part of the overall platform-independent "Java Everywhere" methodology. Basically, if you load the proper platform-specific Java VM on your system, you can then execute any Java program.

By its nature, Java is an interpreted language. With advances in parser technology and add-on packages like just-in-time compilers (JITs), an interpreted language like Java can be executed as fast or, so the debate goes, faster than conventional languages like C. The merits of this argument will not be addressed here.

The Java Development Kit (JDK) can be downloaded from the Sun Java Web site (java.sun.com). Once installed, you can compile, execute and debug Java programs. Alternatively, if the Java Runtime Environment (JRE) is installed, you can execute Java programs but you cannot compile them. Many third-party packages also include a copy of the JVM. The two most common packages to include a JVM are Java integrated development environments and Web browsers. If the JVM is completely embedded within the application, it will not matter which version of the JDK/JRE you have installed on your machine. Alternatively, if an application relies on invoking a pre-installed JVM, care must be taken to ensure that the package can find the proper version of Java.

The following list describes the various noteworthy Java release numbers:

  • 1.0.2 - The release included in, thus supported by, most Web browsers today.
  • 1.1 - The first release that featured, among other things, the new AWT event model, JDBC and bean components.
  • 1.1.3 - Newest released version at the time of this article.
  • 2.0 - Next major release; date: TBA.
If you are developing applets, you still need to adhere to the 1.0.2 standard for now. Future releases of IE and Netscape will support Java version 1.1. If you are developing server-side or standalone Java applications, you can use whatever version of Java you like, since you can control the environment.

Applet Environment
The largest body of Java programs written to date consists of applets. Applets have gained widespread attention mainly because they are used to implement dynamic Graphical User Interfaces (GUIs). While no article regarding Java would be complete without discussing applets, they will not be the main focus of this paper.

In a nutshell, a Java applet is a class file that resides on a Web server which is downloaded to a client upon demand. Once the code is completely downloaded, execution is automatically initiated by the browser.

Applet transfer is initiated when the user points a Web browser at an HTML page containing an APPLET tag. For the APPLET tag to be interpreted properly and the target Java applet executed, the Web browser must be Java compatible (i.e., contain an internal copy of the JVM).

An applet is not totally self-contained. Unlike a C program, which is invoked via the main() function, generally an applet cannot be invoked directly from the command line. (While it is possible to define a main function for an applet that simulates the environment supplied by the browser, that is not an applet requrement.) Applets rely on the environment supplied by the Web browser. Effectively, the browser supplies the main Java function. This function, in turn, calls the applet via four predefined APIs:

  • init() - Called once when the applet is first loaded
  • start() - Called every time the applet (re)gains focus
  • stop() - Called every time the applet loses focus
  • destroy() - Called when the applet is terminated

As an applet programmer, you can implement any or all of the above functions.

In addition to invoking your applet, the browser supplies a sophisticated security paradigm to protect the receiving client host. This sandbox paradigm prevents an applet from performing many operations, such as writing to the local disk, polling external memory, connecting to foreign servers, etc. The scope of the security model will not be discussed further, except to say that it is theoretically impossible to defeat.

Two major benefits can be leveraged by the remote, client-side execution of an applet. By placing GUI manipulation logic in the applet, you can improve the response time of the application while off-loading some of the processing burden on the server CPU. For example, a user could point their browser at a mortgage rate application form and download a pre-qualification applet. The CPU processing of that application would be off-loaded to the client machine. Once the user was happy with the rate, down payment and monthly income values, the applet would notify the server of the finalized loan request.

This, in turn, brings up two issues regarding the ugly underbelly of Java applets. First, before an applet can be invoked, it must be fully downloaded. If your applet is thin - meaning it contains just enough programming logic to support the GUI and application - the download will be fast. If, on the other hand, you make your applet too large (thick), the download time will be too long and the user might terminate the application before the download is completed. Many of the low end Java development tools foster thick Java applets. Care must be taken to ensure that only appropriate client-side code is downloaded via an applet. (This rule varies depending upon who your clients are. If your clients are on a high speed Intranet then larger applets can be tolerated. Conversely, if they connect via 14.4 SLIP connections, then even minimal Java applets might prove to be too large.) Second, since all Java programs consist of machine-independent bytecodes and the resulting bytecodes maintain much of the object base of the high-level language, reverse engineering of the applet is possible. Consequently, by placing large amounts of your core business logic in an applet, you are granting your competition an easy method to obtain a copy of your source code. All they need to do is point their browser at it.

Servlet Environment
A servlet is similar in nature to an applet in that it resides on a Web server and is invoked when a Web browser accesses a Web page. It differs in that a servlet is not downloaded to the client system prior to execution. Consequently, servlets cannot be used to off-load the server CPU's processing burden in that manner. A servlet can reside on another server, thus offering another distributed processing environment option. The big advantage of a servlet over an applet is that your core business logic is protected. Additionally, you can control which version of Java you want to use.

A servlet is considered to be a headless process. Therefore, you cannot perform interactive GUI programming via the Java AWT class. A servlet can generate HTML dynamically, in a similar manner to how a Perl script can read a query string and output HTML codes. In fact, a servlet is designed to be used in place of - or in conjunction with - traditional CGI programming. Most CGI programming is performed in other programming languages, such as: Perl, C, TCL, Python or shell scripts. Using many programming languages results in greater demands upon the developer community and the duplication of utility code. By using Java for both the client and server development environments you help to mitigate these issues. In addition, by implementing Java on the server side, you create a clean API interface between your applets and the server.

Similar to the way an applet relies upon the Web browser environment, a servlet relies upon the environment supplied by the Web server. Unfortunately, this interface varies depending upon which Web server you are running. For example: If you are programming against either Netscape's Enterprise or Fast Track Servers, then the invocation API is the run() method. With Sun's newly released Java Web Server, formerly called Jeeves, it is the service() method. Sun is attempting to resolve the multiple API problem by defining the Servlet API to be released in the java.servlet package (mid '97). Once your servlet has been invoked, other methods exist to enable processing of the URL/CGI data. The details of this processing are beyond the scope of this article. It is likely that the new java.servlet package will not make it into the new Netscape server that is soon to be released, although you can download and install the package yourself.

Servlets have an interesting side effect. They are neither CGI programs nor plug-ins (discussed below). Consequently, when you invoke a servlet the server does not have to spawn an entirely new process, as it would for a CGI program. Alternatively, since you are not directly binding your servlet image to the Web server via a shared library, you do not run the risk of crashing the server due to a programming logic error. Java servlets have a realistic potential to replace traditional CGI programming in medium to large Web site development shops as early as mid 1998.

Server API Environment
As mentioned above, many Web servers provide an API whereby you can bind an application program to the Web server process itself. This operation is sometimes referred to as creating a plug-in. Server API interfaces vary with the Web server manufacturer. Two of the more popular API interfaces are Netscape's NSAPI and Microsoft's ISAPI.

In essence, a plug-in is created by generating a shared library (UNIX) or a DLL (NT) and binding it with the Web server. Most plug-ins are programmed in C or C++. Because a plug-in interfaces directly to the Web server's executable object, you get your best performance gain. Unfortunately, if you should have a bug in your code your Web server can core dump, thus crashing the server.

Currently, no plug-in interface exists for a Java servlet. In fact, the concept of a plug-in does not apply to Java programs. By its nature, a Java program does not compile to machine code. Thus, you cannot generate a shared library or DLL. While there are several compilers available that can compile a Java program to native machine code, library generation is not a feature.

As Java stabilizes and becomes more popular, the ability to generate a library might emerge. Currently, the focus with Java is on "100% Pure, Cross Platform Support." While this issue rages, the issue of using Java for inherently non-cross platform applications will get virtually no attention. Over the next five years, Java compilers that can be used in place of traditional high level languages, say C++, will be developed. At present little work is being done (at least publicly) on native Java compilers.

Server CGI Programs
CGI is the oldest and easiest of interfaces to work with in the Web server environment. In its simplest form, you cite a CGI program's name in an HTML file along with what parameters you want passed. When the user references the link, the Web server packages the environment variables into a name=value string, performs some encoding and then invokes the program. The CGI program must then decode the string and split out the name/value pairs. Numerous utilities exist that will perform this decoding.

When attempting to use Java as a CGI program, you run into an interesting problem. Assuming that the main() method has been defined, you cannot invoke a Java program directly. Instead, you must invoke the Java Virtual Machine and pass it the name of the Java class file that you want to run. Furthermore, you must pass all runtime information manually, including the CLASSPATH and any necessary Web server environment variables (the most notable server environment variable being the URL-encoded query string).

For example, if you have written a Java program called ProcessForm.java, you would invoke the process as follows:

java ProcessForm $QUERY_STRING

Unfortunately, in a URL there is no way to pass this information. The URL string would have to look something like:

http:www.yoursite.com/java<sp>ProcessForm?n1=v1&n2=v2

The problem is that there can be no spaces in a URL. In the above example, a space exists between the words "java" and "ProcessForm". A legal, encoded URL would have the following form:

http:www.yoursite.com/java?ProcessForm&n1=v1&n2=v2

This assumes that the Java Virtual Machine knows how to process and decode this URL - which it doesn't. Furthermore, even if the VM knew how to decode the URL as part of the security paradigm, it does not pass environment variables. Consequently, none of the server/CGI environment variables (query string, server name, reference URL, etc.) would be available to the Java-based CGI program.

The ultimate solution to this problem is to write a shell script that packages all the necessary environment variables and invokes the JVM with your target Java program. Such a shell script is depicted in Listing 1, CGI Wrapper Script. Within your Java program you can then extract the environment variables and insert them into Java's equivalent of an associative array - a properties table. Listing 2, Java CGI Program, depicts a Java program that parses the input string, first by the "&" character and then by the "=" character. For each token/value pair that it finds, it inserts the value into a properties table called TVtable. Other environment variables that are passed (via the -D option) are automatically placed in the system properties table. [Note: Unmangling of the URL encoded string is left to the reader].

This wrapper script does not buy you much in terms of speed (and I am not referring to the somewhat inefficient implementation structure of the script, but rather, the processing overhead). When invoking a Java program via a wrapper script, you inherit all of the startup overhead that is associated with standard CGI programming and more. Namely: The OS must spawn off a new heavyweight process (duplicating the process space of the parent), start the wrapper script, start the Java VM and finally, start the Java application.

One might wonder what the justification of such an approach might be. If you are currently running a Web server that does not support servlets and you want to experiment with Server Side Java, then this approach will enable SSJ calls. In addition, you can download the java.servlet class from Sun and start using the HTML processing methods that are defined. While your main() method programming logic will not be portable to the newer server-side Java environment, the core logic of the servlets will be.

Standalone Programs
So far, we haven't gotten too far afield of the Internet environment. For Java to be truly considered an enterprise solution, it needs to be integrated into the entire organization. This means using Java for non-Web based (i.e., standalone or embedded) applications. For this to happen, the process of invoking a standalone Java program must be made as simple as starting a normal binary executable.

In the previous example, CGI Wrapper Script, we made some basic assumptions that enabled us to automatically invoke our Java program without hardcoding the name. For example, the name of the target Java class was assumed to be the same as the name of the script. This is evident in the line:

JavaClass=$(basename $0)

Later in the program, "JavaClass" is passed to the Java VM as the name of the class file to interpret. Unfortunately, the script does not perform quite enough logic to allow us to start a Java program simply by entering the class name. For example, the wrapper script assumes that the script and class file both reside in the current directory.

In order to have a script that automates the startup of a Java program, several key assumptions must be made. The code depicted in Listing 3, Standalone Wrapper Script, makes the following assumptions:

  1. The name of the wrapper script matches the name of the class file.
  2. The wrapper script is installed in a directory along the PATH specification.
  3. The class file is installed in a sub-directory under the wrapper script directory.
  4. The sub-directory containing the class file is named after the wrapper script with an "_bin" appended to the name.
Consequently, if the wrapper script is named MyApp then the path specification to the class file is:

.../MyApp_bin/MyApp.class

After gathering this information, the wrapper script adds the bin and _bin directory names to the class path environment variable and invokes the Java VM.

The only remaining issue is: How should your standalone Java program handle usage information, option parsing and on-line help. Listing 4, Standalone Java Program, depicts an example main() method. This standalone application does the following:

  1. Parse Tokens - Parsing starts with the first token found on the command line. Note that there is no $0 argument in Java associated with the name of the executing program. It parses each token, provided the token starts with a dash "-" in the first character position.
  2. Match Key Words - As part of the parsing process, the code checks for full or partial words (-verbose vs. -v). If a match is found, a local variable is set. If an illegal switch is encountered, an error message is displayed and the process terminates.
  3. If the help (-help or -h) option is encountered, then a menu of legal switches is displayed, along with their meaning. The usage line is then displayed and execution is terminated.
  4. Finally, a comparison is made regarding the remaining number of arguments vs. the expected number. If the two numbers don't match or an error was encountered during the switch parsing process, the usage line is displayed and processing is terminated.

After this processing is completed, application processing can be started. Given this type of usage/error checking, a standalone Java application would look and behave like a normal function. (Mind you, this is a UNIX-centric view of life. The standalone application could easily be modified to act like a DOS function.)

Again, the question remains: What are the benefits of going to the trouble of writing standalone Java functions? This question will be answered in the next section.

The Future
It has been said that Nineteen Hundred Ninety Six was the year of Java - it was not. 1996 was undoubtedly the year of the Java applet. As things are shaping up, 1998 will be the year of Java as it moves from the domain of the Internet to the entire enterprise. (It will be widely reported that it will be 1997, until 1998 comes along and we realize that 1997 was the year of the servlet.)

In 1998, Java will become fully integrated into the OS kernel of all major UNIX platforms and, possibly, NT. Both the network computer (NC) and the network PC (netPC) will implicitly understand Java class files because they will run the Java operating system (JavaOS).

Eventually, wrapper scripts will no longer be necessary. Traditional CGI programming will continue to be done in only the smallest of Web site development shops. You will be equally as able to deploy Java for an application as you would other high level languages. Finally, many traditionally platform-specific packages (word processors, spread sheets, etc.) will be retooled in Java and released in platform-independent versions.

If you start using Java now - via wrapper scripts, servlets, applets, etc. - you will find yourself ahead of the pack.

About the Author
Ken Kranz is the director of Internet Services for Interaxis Corporation, a developer of database driven Web sites. He can be reached at [email protected]

	

Listing 1: CGI Wrapper Script.
 
#!/sbin/ksh 
BASENAME=$(basename $0) # the name of this script 
JAVA=$(which java)  # the path to the VM 

if (( $# < 1 )); then 
   echo "$BASENAME: $# arguments found, at least 1 expected." >&2 
   echo "Usage: $BASENAME [-options] ClassFile GetString" >&2 
   exit -1 
fi 

JavaClass=$(basename $0) # assume the class name matches the script 
JavaDir=$(dirname $1)  # get the current directory name 
GetString=$2 

# build the system properties entries 
for Property in REMOTE_HOST HTTP_HOST HTTP_CONNECTION SERVER_SOFTWARE \ 
 DOCUMENT_NAME SERVER_URL SERVER_NAME \ 
 SERVER_PORT REMOTE_ADDR TZ DOCUMENT_URL 
do 
   # setup an option string that passes in all env variables 
   Temp=$(env | grep $Property) 
   Name=$(echo $Temp | cut -d= -f1) 
   Value=$(echo $Temp | cut -d= -f2) 
   if [[ $Name != "" ]]; then 
      SystemProperties="$SystemProperties -D\"$Temp\"" 
   fi 
done 

# add current dir to the class path 
if [[ $JavaDir != "" ]]; then 
   export CLASSPATH=$CLASSPATH:$JavaDir 
fi 
# invoke the VM on the target class file, pass the get string 
$JAVA $SystemProperties $JavaClass $GetString 

Listing 2: Java CGI Program.
 
import java.util.*; 

public class cgiParse extends Properties { 
  private Properties TVtable; 
  private StringTokenizer MetaToken; 

  public static void main (String args[]) { 
    cgiParse myTable = new cgiParse(); 
    // note the shell script wrapper checks for illegal args 
    myTable.parse(args[1]); 
  } 
  

  public void parse (String cli) { 

    TVtable = new Properties(); 
    MetaToken = new StringTokenizer(cli, "&"); 

    while (MetaToken.hasMoreTokens()) { 

      String NextToken = MetaToken.nextToken(); 
      StringTokenizer KeyValue = new StringTokenizer(NextToken, "="); 

      String Key   = KeyValue.nextToken();      
	  // extract the Key part 
      String Value = KeyValue.nextToken();      
	  // extract the Value art 

      // if the key is already in the table then append the new value 
      // else insert the new key/value pair 
      if (TVtable.containsKey(Key)) { 
        // key already exists, append the new value 
        String OldValue = TVtable.getProperty(Key); // get the old value 
        TVtable.remove(Key);                        // remove old entry 
        // append the new value and insert back into the table 
        TVtable.put(Key, OldValue+" "+Value); 
      } else { 
  # insert anew  
        TVtable.put(Key, Value); 
      } 
    } 
  } 
} 

Listing 3: Standalone Wrapper Script.
 
#!/sbin/ksh  # Eg Filename: MyApp 
BASENAME=$(basename $0)  # MyApp 
ME=$(whence $0 )  # /usr/local/javabin/MyApp 
CLASS=${BASENAME}.class  # MyApp.class 

PATH2ME=$(dirname $ME )  # eg: /usr/local/javabin 
PATH2CLASS=${PATH2ME}/${BASENAME}_bin # eg: /usr/local/javabin/MyApp_bin 
cd $PATH2CLASS # go to the dir w/ the class file 

if [[ ! -a $CLASS ]]; then  # if no class file, exit 
   echo "$BASENAME: unable to locate target: $CLASS" >&2  
   exit 1  
fi  

export CLASSPATH=$PATH2CLASS:$PATH2ME:$CLASSPATH  

java $BASENAME [email protected]  # java MyApp [args] 

Listing 4: Standalone Java Program.
 
import java.util.*; 

class MyApp { 

   public static void main(String args[]) { 

      int verboseLevel   = 0 ; 
      boolean helpFlag   = false; 
      String usage       = "-v[erbose] -h[elp]"; 
      int ArgSpec        = 1;       
// minimum number of expected arguments 
      int switchCount    = 0;       
// number of switches found 
      boolean CLIError   = false;   
// user invocation error 

      for (int i=0; i < args.length; i++) { 
         if (args[i].equals("-verbose") || args[i].equals("-v")) { 
            verboseLevel++; 
            switchCount++; 

         } else if (args[i].equals("-help") || args[i].equals("-h")) { 
            helpFlag = true; 
            switchCount++; 

         } else if (args[i].startsWith("-", 0)) { 
            System.err.println("Illegal switch: " + args[i]); 
            CLIError = true; 
            switchCount++; 
         }  
      } 

      if (helpFlag) { 
         System.out.println("" + 
         "   -v[erbose]   Increase verboseness level\n" + 
         "   -h[elp]      Display this on-line help message\n"); 
         System.err.println("Usage: " + usage); 
         System.exit(0); 
      }      

      int totalArgs = args.length - switchCount; 
      int firstArgOff  = switchCount; 
      if (ArgSpec != totalArgs) { 
         System.err.println(totalArgs + " arguments found " +  
            ArgSpec + " expected\n"); 
         System.err.println("Usage: " + usage); 
         System.exit(1); 
      } else if (CLIError) { 
         System.err.println("Invalid/illegal switches encountered"); 
         System.err.println("Usage: " + usage); 
         System.exit(2); 
      }      
   } 
}


 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.