Factors that Influence Platform Independence
Java’s architecture facilitates the creation of platform-independent software, but also allows you to create software that is platform-specific. When you write a Java program, platform independence is an option.
The degree of platform independence of any Java program depends on several factors. As a developer, some of these factors are beyond your control, but most are within your control. Primarily, the degree of platform independence of any Java program you write depends on how you write it.
Java Platform Deployment
The most basic factor determining the a Java program’s platform independence is the extent to which the Java Platform has been deployed on multiple platforms. Java programs will only run on computers and devices that host a Java Platform. Thus, before one of your Java programs will run on a particular computer owned by, say, your friend Alicia, two things must happen. First, the Java Platform must be ported to Alicia’s particular type of hardware and operating system. Once the port has been done by some Java Platform vendor, that port must in some way get installed on Alicia’s computer. So a critical factor determining the true extent of platform independence of Java programs–and one that is beyond the control of the average developer–is the availability of Java Platform implementations and their distribution.
Fortunately for the Java developer, the deployment of the Java Platform has proceeded with great momentum, starting with Web-browsers, then moving on to desktop, workstation, network operating systems, and into many different kinds of consumer and embedded devices. It is increasingly likely, therefore, that your friend Alicia will have a Java Platform implementation on her computer or device.
The Java Platform Version and Edition
The deployment of the Java Platform is a bit more complicated, however, because not all standard runtime libraries are guaranteed to be available at every Java Platform. The basic set of libraries guaranteed to be available at a Java Platform is called the standard API. Sun calls a 1.2 Java virtual machine accompanied by the class files that constitute the standard API the Java 2 Platform, Standard EditionThis edition of the Java Platform has the minimum set of Java API libraries that you can assume will be available at desktop computers and workstations. But as described earlier, Sun also defines API sets for the Micro and Enterprise Editions of the Java 2 Platform, and encourages the development of API profiles to augment the Micro Edition in various consumer and embedded industry segments. In addition, Sun defines some standard runtime libraries that it considers as optional for the Standard Edition, and calls these Standard Extension APIs. These libraries include such services as telephony, commerce, and media such as audio, video, or 3D. If your program uses libraries from the Standard Extension API, it will run anywhere those standard extension API libraries are available, but not on a computer that implements only the basic Standard Edition Platform. Some of the Standard Extension APIs, on the other hand, are guaranteed to be available at any implementation of the Enterprise Edition. Given the variety of API editions and profiles, the Java 2 Platform hardly represents a single homogeneous execution environment that will in all cases enable code that is written once to run anywhere.
Another complicating factor is that in a sense the Java Platform is a moving target–it evolves over time. Although the Java virtual machine is likely to evolve very gradually, the Java API will probably change more frequently. Over time, features will be added to and removed from both the Standard Edition and Standard Extension APIs, and parts of the Standard Extension API may migrate into the Standard Edition. The changes made to the Java Platform should for the most part be upwards compatible, meaning they won’t break existing Java programs, but some changes may not be. As obsolete features are removed in a new version of the Java Platform, existing Java programs that depend upon those features won’t run on the new version. Also, changes may not be downwards compatible, meaning programs that are compiled for a new version of the Java Platform won’t necessarily work on an old version. The dynamic nature of the Java Platform complicates things somewhat for the developer wishing to write a Java program that will run on any computer.
In theory, your program should run on all computers that host a Java 2 Platform, Standard Edition, so long as you depend only upon the runtime libraries in the standard API. In practice, however, new versions of the standard API will take time to percolate everywhere. When your program depends on newly added features of the latest version of the standard API, there may be some hosts that can’t run it because they have an older version. This is not a new problem to software developers–programs written for Windows 95, for example, didn’t work on the previous version of the operating system, Windows 3.1–but because Java enables the network delivery of software, it becomes a more acute problem. The promise of Java is not only that it is easy to port programs from one platform to another, but that the same piece of binary Java code can be sent across the network and run on any computer or device.
As a developer, you can’t control the release cycles or deployment schedules of the Java Platform, but you can choose the Java Platform edition and version that your programs depend upon. In practice, therefore, you will have to decide when a new version of the Java Platform has been distributed to a great enough extent to justify writing programs for that version.
Besides the Java Platform version and edition your program depends on, the other major factor determining the extent of platform independence of your Java program is whether or not you call native methods. The most important rule to follow when you are writing a platform independent Java program is: don’t directly or indirectly invoke any native methods that aren’t part of the Java API. As you can see in Figure 2-1, calling native methods outside the Java API renders your program platform-specific.
Figure 2-1. A platform-specific Java program.
Calling native methods directly is appropriate in situations where you don’t desire platform independence. In general, native methods are useful in three cases: o for accessing features of an underlying host platform that are not accessible through the Java API o for accessing a legacy system or using an already existing library that isn’t written in Java o for speeding up the performance of a program by implementing time-critical code as native methods
If you need to use native methods and also need your program to run on several platforms, you’ll have to port the native methods to all the required platforms. This porting must be done the old fashioned way, and once you’ve done it, you’ll have to figure out how to deliver the platform-specific native method libraries to the appropriate hosts. Because Java’s architecture was designed to simplify multi-platform support, your initial goal in writing a platform-independent Java program should be to avoid native methods altogether and interact with the host only through the Java API.
Non-Standard Runtime Libraries
Native methods aren’t inherently incompatible with platform independence. What’s important is whether or not the methods you invoke are implemented “everywhere.” Implementations of the Java API on operating systems such as Windows or Solaris use native methods to access the host. When you call a method in the Java API, you are certain it will be available everywhere. It doesn’t matter if in some places the method is implemented as a native method.
Java Platform implementations can come from a variety of vendors, and although every vendor must supply the standard runtime libraries of the Java API, individual vendors may also supply extra libraries. If you are interested in platform independence, you must remain aware of whether any non-standard runtime libraries you use call native methods. Non-standard libraries that don’t call native methods don’t degrade your program’s platform independence. Using non-standard libraries that do call native methods, however, yields the same result as calling native methods directly–it renders your program platform-specific.
Virtual Machine Dependencies
Two other rules to follow when writing a platform independent Java program involve portions of the Java virtual machine that can be implemented differently by different vendors. The rules are: 1. don’t depend upon timely finalization for program correctness, and 2. don’t depend upon thread prioritization for program correctness. These two rules address the variations allowed in the Java virtual machine specification for garbage collection and threads.
All Java virtual machines must have a garbage-collected heap, but different implementations can use different garbage collection techniques. This flexibility in the Java virtual machine specification means that the objects of a particular Java program can be garbage collected at completely different times on different virtual machines. This in turn means that finalizers, which are run by the garbage collector before an object is freed, can run at different times on different virtual machines. If you use a finalizer to free finite memory resources, such as file handles, your program may run on some virtual machine implementations but not others. On some implementations, your program could run out of the finite resource before the garbage collector gets around to invoking the finalizers that free the resource.
Another variation allowed in different implementations of the Java virtual machine involves thread prioritization. The Java virtual machine specification guarantees that all runnable threads at the highest priority in your program will get some CPU time. The specification also guarantees that lower priority threads will run when higher priority threads are blocked. The specification does not, however, prohibit lower priority threads from running when higher priority threads aren’t blocked. On some virtual machine implementations, therefore, lower priority threads may get some CPU time even when the higher priority threads aren’t blocked. If your program depends for correctness on this behavior, however, it may work on some virtual machine implementations but not others. To keep your multi-threaded Java program platform independent, you must rely on synchronization–not prioritization–to coordinate inter-activity between threads.
User Interface Dependencies
Another major variation between different Java Platform implementations is user interface. User interface is one of the more difficult issues in writing platform independent Java programs. The AWT user interface library gives you a set of basic user-interface components that map to native components on each platform. The Swing library gives you advanced components that don’t map directly to native components. From this raw material, you must build an interface that users on many different platforms will feel comfortable with. This is not always an easy task.
Users on different platforms are accustomed to different ways of interacting with their computer. The metaphors are different. The components are different. The interaction between the components is different. Although the AWT and Swing libraries make it fairly easy to create a user interface that runs on multiple platforms, they don’t necessarily make it easy to devise an interface that keeps users happy on multiple platforms.
Bugs in Java Platform Implementations
One final source of variation among different implementations of the Java Platform is bugs. Although Sun has developed a comprehensive suite of tests that Java Platform implementations must pass, it is still possible that some implementations will be distributed with bugs in them. The only way you can defend yourself against this possibility is through testing. If there is a bug, you can determine through testing whether the bug affects your program, and if so, attempt to find a work-around.
Given the allowable differences between Java Platform implementations, the platform dependent ways you can potentially write a Java program, and the simple possibility of bugs in any particular Java Platform implementation, you should if possible test your Java programs on all platforms you plan to claim it runs on. Java programs are not platform independent to a great enough extent that you only need test them on one platform. You still need to test a Java program on multiple platforms, and you should probably test it on the various Java Platform implementations that are likely to be found on each host computer you claim your program runs on. In practice, therefore, testing your Java program on the various host computers and Java Platform implementations that you plan to claim your program works on is a key factor in making your program platform independent.