Chapter 25. Standard Packages

 

No unmet needs exist, and current unmet needs that are being met will continue to be met.

 
 --Transportation Commission on Unmet Needs, California

The Java 2 Platform Standard Edition comes with many standard packages. These packages, all subpackages of the root java package, define the main classes and interfaces for the platform. Throughout this book we have taught you about many of these classes, particularly those relating to the core language and those most commonly used in general programs. The main packages that we have covered are

  • java.lang—. The main language classes, such as Object, String, Thread, Class, and so on. The subpackage java.lang.annotation defines some annotation types and was covered in Chapter 15. The subpackage java.lang.reflect provides a way to examine types in detail and was covered in Chapter 16. The subpackage java.lang.ref defines the weak reference types that allow you to influence garbage collection and was covered in Chapter 17.

  • java.io—. Input and output and some file system manipulation. This package was covered extensively in Chapter 20.

  • java.util—. Classes of general utility. Defines the collection classes both new and legacy that were covered in Chapter 21 and the localization classes covered in Chapter 24. Miscellaneous utilities were covered in Chapter 22.

  • java.util.regex—. Classes for regular expressions. These were covered in Chapter 13.

  • java.security—. The platform security classes, which were briefly described in Chapter 23. It contains a number of other classes for encryption, authentication, digital signatures, and other useful security-related code.

  • java.text—. Internationalization and localization for formatting and parsing numbers and dates, sorting strings, and message lookup by key. These were touched on briefly in Chapter 24.

We mentioned these main packages briefly, without covering them in detail:

  • java.nio—. The “New I/O” classes that we briefly introduced at the end of Chapter 20. The CharBuffer class from this package also pops up in a couple of other places.

  • java.nio.charset—. Classes for defining character sets and their encodings. This package was briefly covered in Chapter 13.

  • java.util.concurrent—. Contains (amongst other things) the concurrent collections that were briefly discussed in Chapter 21.

In addition, there are main packages we haven't covered at all:

  • java.awt—. The Abstract Window Toolkit abstraction layer for writing platform-independent graphical user interfaces.

  • java.applet—. The Applet class and related types for writing subprograms that can be hosted inside other applications, such as HTML browsers.

  • java.beans—. The JavaBeans components for user-composable code.

  • java.lang.instrument—. Services for defining agents that can instrument applications running on a virtual machine.

  • java.lang.management—. Services for monitoring and managing both the virtual machine and the operating system on which it runs.

  • java.math—. Mathematical manipulations. Currently, this package has only three classes, which handle some kinds of arbitrary-precision arithmetic.

  • java.net—. Networking classes for sockets, URLs, and so on.

  • java.rmi—. Remote Method Invocation, with which you can invoke methods on objects running in other virtual machines, typically across a network.

  • java.sql—. The JDBC package for using relational databases.

  • java.util.jar—. Classes for reading and writing JAR (Java ARchive) files. These archive files can be used to distribute packages of related classes and resources, as covered in “Package Objects and Specifications” on page 477.

  • java.util.logging—. A framework for logging from within your code.

  • java.util.prefs—. Provides a mechanism for managing user and system preferences, as well as application configuration.

  • java.util.zip—. Classes for reading and writing ZIP files.

Further packages exist outside the java package of the platform, in what are known as the standard extensions, for example:

  • javax.accessibility —. A framework for developing GUIs that are more accessible to people with disabilities.

  • javax.naming—. Classes and subpackages for working with directory and naming services.

  • javax.sound—. Has subpackages for creating and manipulating sounds.

  • javax.swing —. The Swing package of GUI components.

And there are packages that provide interaction between the platform and other environments:

  • org.omg.CORBA —. Classes for the Common Object Request Broker Architecture (CORBA), object request brokers (ORB's).

  • org.omg.CosNaming —. The Common Object Service's naming classes.

Other versions of the platform, such as the Java 2 Platform Enterprise Edition, contain even more packages.

This book cannot be large enough to contain full coverage of every one of these packages—some of them require complete books of their own. This chapter discusses some of the java subpackages not otherwise covered in this book, giving an overview of the purpose and contents, as well as some of the other packages we have listed. All these packages are covered in detail in your local documentation and the java packages are covered in the volumes of The Java Class Libraries, Second Edition. Most of the java packages, including the AWT and applet packages and some extensions such as Swing, are taught in the different versions of The Java Tutorial. These books and all others cited in this chapter are part of this official series of documentation from the source—the people who invented the Java programming language, its virtual machine, and many of its packages.

java.awt — The Abstract Window Toolkit

The Abstract Window Toolkit allows you to write graphical user interfaces (GUIs) that will run on every system in a reasonable way. The AWT displays GUI components (such as buttons, labels, and text fields) using (by default) the local platform's look and feel, showing Macintosh buttons on a Mac, Motif buttons on X platforms, Windows buttons on Windows systems, and so on.

For this to work, you may need to change how you think about laying out your GUI. You may be accustomed to interactive tools that let you place the various GUI components on the screen exactly where you want them to be. Such absolute placement will not work for a portable interface because, for example, the size of a button is different on different systems. When your interface is used on a system other than the one on which you designed it, some buttons will overlap and others will have ugly gaps between them.

Although you can use absolute placement in AWT, it is not recommended. When you place a component into an AWT display frame, the frame's layout manager decides where to put it. Almost all the layout managers provided with the AWT use relative placement: Components are placed and sized relative to other components. All the provided layout managers implement either the interface LayoutManager or its extended interface LayoutManager2. Layout managers range from the simple (FlowLayout adds components to a line until they don't fit and then starts a new line) to the sophisticated (GridBagLayout has a great deal of flexibility). You can also write your own layout manager.

Instead of thinking about where a check box should go on the screen, you should think about how it should be placed relative to other components. Then choose a layout manager for the frame in which the check box will be placed and add the components so that they have the expected relationships. If you do this right, your interface will look clean on all platforms.

AWT has a set of standard GUI components: labels, buttons, check boxes, choice lists, scroll bars, text fields, text regions, and so on. Several top-level containers, such as dialog boxes and windows, let you place other components inside them (preferably using a relative-placement layout manager).

When you need to draw your own graphics on the screen, the simplest technique is to subclass Component or Container, overriding the paint method to draw what you need using the Graphics object passed to paint. Component is the basis for many customized user-interface components when no standard component does what is needed. You would subclass Container if your drawn component contained other components.

The AWT is an event-based system. When the user performs an action, such as moving a mouse, clicking a mouse button, or typing a key, an event is generated that identifies the underlying component as the source of that event and that encapsulates the nature of that event. The event is then placed in a central event queue, and will be serviced by a single event thread. The event thread takes events from the queue one at a time and dispatches them to their source components. You can also generate events programmatically—for example, invoking repaint on a component puts an UPDATE event into the event queue—or can create event objects and insert them directly into the event queue.

Components are notified of events (mouse up, mouse down, mouse drag, keyboard events, and the like) by having methods invoked on them by the event thread. You can also register listener objects that are notified when an event occurs within a component. For example, a button that lets the user exit the program might be set up like this:

Button b = new Button("Exit");
b.addActionListener(
    new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            System.exit(0);
        }
    }
);
gui.add(b);

Action events come from the basic action on the component, such as pressing a button or selecting a check box. The ActionEvent class has details of an action event, such as the keyboard modifiers (such as the Alt or Control key) that were being pressed when the action occurred. To receive this event you must register interest in action events, either by adding an ActionListener to the component as shown here or by invoking enableEvents with an appropriate mask.

The ActionListener interface in the previous example is a listener interface. Listener interfaces extend java.util.EventListener and exist for many kinds of events: mouse, keyboard, window, item, text, container, and general component events. You use objects that implement listener interfaces to trigger method execution when events occur—all of which get executed by the event thread. When an event occurs, the component's processEvent method is called, which in turn calls processXXXEvent for the specific event, and that in turn will call the XXXOccurred method of all registered listeners for that event.

Other classes in java.awt allow you to set colors, fonts, and so on. All these properties are inherited by default from outer components—the default colors of a button are those of the frame in which it has been placed. You can override this setting at any level by explicitly specifying a color for a component. That component and all its contained components will change to the specified color unless a subcomponent has its color specified.

Various subpackages of java.awt allow you to manipulate images, sounds, and other media:

  • java.awt.color—. color manipulation tools

  • java.awt.datatransfer—. moving data between applications, such as with cut, copy, and paste

  • java.awt.dnd—. drag-and-drop functionality

  • java.awt.event—. various event listener and adapter classes for connecting events to your code

  • java.awt.font—. font manipulation APIs

  • java.awt.geom—. 2D geometry

  • java.awt.im—. input method interfaces for localized input devices

  • java.awt.image—. several interfaces and classes for reading and manipulating images

  • java.awt.print—. printing APIs

java.applet — Applets

Applets are a way to run code inside another application—commonly a web browser. Applets are the first exposure many people have to the Java virtual machine and its uses. An applet is defined primarily by the protocol that governs its lifetime and the methods by which it can query and manipulate its runtime environment. The types in java.applet—primarily the Applet superclass itself—define this environment.

When an <applet> or <object> tag is found in a web page's HTML, the browser downloads the code for the named class from a URL, creates an object of that class, creates a region on the web page for that object to control, and then invokes the object's init method—often creating a ThreadGroup and Thread just for this applet. As the applet runs, it can download other classes from the server as needed. Applets are usually run in a tightly secured “sandbox” in which potentially dangerous operations (such as file access, network access, and running local programs) are restricted by the security policy.

The method init is one of four lifecycle methods defined for the applet in the Applet class. After init is called, start is called, which tells the applet that it is active and should perform its function. If the browser decides that the applet is no longer of interest to the user, for example, the user leaves the page the applet was on, the applet's stop method is invoked to tell it to stop what it was doing. If the user returns to the applet's page the browser may invoke start again to tell the applet to recommence—so the applet can cycle through a stop–start sequence as the user presses the “Back” and “Forward” buttons (or their equivalents) to visit and leave the page. When the browser decides that the applet is no longer of interest (perhaps because the user has moved a number of pages away) the applet's destroy method is invoked to free up any resources used by the applet. If the applet's page is now revisited the lifecycle will recommence with init being called again. The browser ultimately defines the lifecycle of an applet and may choose to invoke destroy immediately after stop when the user leaves the page. Whether or not an applet class is unloaded and reloaded between visits to the applet is again a feature of the browser.

These lifecycle methods are typically overridden by applet classes. For example, if an applet uses a thread to do its work, init would typically create the thread; start would invoke the thread's start method the first time and ask it to continue execution on subsequent invocations; stop could ask the thread to pause to prevent it from consuming resources while the page is not visible; and destroy could interrupt the thread because the thread would no longer be needed.

An applet can get parameters from a <param> tag to customize its behavior. It might get colors, fonts, or the URL of an image to display.

Applets usually run in a highly constrained security environment to protect your computer and network from unwelcome inspection or invasion by a hostile applet. This means that certain conveniences, such as a local scratch disk, may not be available by default. You can grant permission to perform particular actions to individual applets by specifying an appropriate security policy.

The applet model is a good example of how the Java platform provides power. The fact that the same code runs on all systems in the same way allows a single piece of code (an applet) to run in a variety of browsers on a variety of windowing systems running on a larger variety of operating systems. The portability of Java bytecodes allows you to execute part of your application on the server and another part on the client system via downloaded code, whichever is appropriate. It is the same platform on both sides: the Java virtual machine. The ability to move code from one place to another and execute it in a secure environment enables new ways of thinking about where to execute what part of your design.

java.beans — Components

The JavaBeans component architecture helps independent vendors write classes that can be treated as components of larger systems assembled by users. The java.beans package provides necessary and useful classes for writing such beans. A bean exports properties, generates events, and implements methods. By following certain design patterns or by implementing methods that provide a description of these facets of behavior, you can compose beans by using interactive tools to build a system the user needs.

Much of a bean's behavior is simplified if you follow expected design patterns. For example, if your bean class is called Ernest and you provide a class named ErnestBeanInfo that implements the BeanInfo interface, the JavaBeans tools will use ErnestBeanInfo as a source of information about the behavior of the bean: the events it supports, the icons it uses, and so on.

Providing a BeanInfo object is itself optional—the JavaBeans system will use reflection to infer events and properties. For example, if a class Ernest has methods named getImportance and setImportance, the JavaBeans system will assume that you have an importance property that can be set, either directly or via another bean. Builder tools are expected to present the properties and events to users, who can use them to connect beans as components to build custom applications.

AWT components are beans, and the event model described earlier for AWT components is also the JavaBeans event model.

The JavaBeans component architecture is designed to interoperate with existing component architectures, extending the “Write Once, Run Anywhere” capability to create a homogeneous component platform.

The subpackage java.beans.beancontext defines interfaces and classes that are used to talk about the context in which a bean or set of beans is executing. Bean contexts can be nested.

java.math — Mathematics

The package java.math is destined for classes that help with mathematical calculations. Currently, it has three classes—BigInteger, BigDecimal and MathContext—and an enum, RoundingMode, that defines different rounding modes.

The class BigInteger provides arbitrary-precision integer arithmetic, providing analogous operations for all integer operations except >>>, which is equivalent to >> because there is no sign bit to copy in an arbitrary-precision integer. Neither will the provided single-bit operations (clearBit and setBit) change the sign of the number on which they operate. BigInteger behaves as if it were defined in two's-complement notation—the same notation used by the primitive integer types. Binary bitwise operations start by extending the sign of the smaller number and then executing the operation, just as operations on primitive values do. BigInteger objects are immutable, so all operations on them produce new BigInteger objects. The following simple method returns an iterator over the prime factors of a number:

static final BigInteger ONE = BigInteger.valueOf(1);
static final BigInteger TWO = BigInteger.valueOf(2);
static final BigInteger THREE = BigInteger.valueOf(3);
public static Iterator<BigInteger> factors(BigInteger num) {
    ArrayList<BigInteger> factors = 
        new ArrayList<BigInteger>();

    if (num.compareTo(ONE) <= 0) { // num<=ONE means skip it
        factors.add(num);
        return factors.iterator();
    }

    BigInteger div = TWO;                     // divisor
    BigInteger divsq = BigInteger.valueOf(4); // div squared

    while (num.compareTo(divsq) >= 0) {
        BigInteger[] res = num.divideAndRemainder(div);
        if (res[1].signum() == 0) { // if remainder is zero
            factors.add(div);
            num = res[0];
        } else {                    // try next divisor
            if (div == TWO)
                div = THREE;
            else
                div = div.add(TWO);
            divsq = div.multiply(div);
        }
    }
    if (!num.equals(ONE))   // leftover must be a factor
        factors.add(num);
    return factors.iterator();
}

The constants ONE, TWO, and THREE are used often, so we create objects for them once. If the number we are factoring is less than or equal to one, we treat it as its own factor (BigInteger and BigDecimal implement the Comparable interface described on page 574). After this validity test we perform the real work of the method: testing potential divisors. If a divisor divides into the number evenly, it is a prime factor, and we proceed with the result of the division to find more factors. We first try two, and then all odd numbers, until we reach a divisor whose square is larger than the current number. You could optimize this method in any number of ways, but it shows how to use some BigInteger functionality.

BigDecimal provides an arbitrary-precision signed decimal number consisting of an arbitrary-precision integer and an int scale that says how many decimal places are to the right of the decimal point. The actual precision required can be set through a MathContext object that is either associated with the BigDecimal at construction time or passed as an argument to the actual operation being performed.

Decimal division and changing a number's scale require rounding, which you can specify on each operation or through an associated MathContext object. You can require that rounding be up, down, toward zero, away from zero, or toward the nearest value. You can also assert that no rounding will be necessary, in which case ArithmeticException will be thrown if you are found to be wrong. The eight different rounding modes are defined by the RoundingMode enum.

java.net — The Network

The java.net package provides classes for working with network infrastructure, such as sockets, network addresses, Uniform Resource Identifiers (URIs), and Uniform Resource Locators (URLs).

The java.net package is centered around the Socket class, which represents a connection to another socket—possibly on another machine—across which bytes can flow. You typically create a socket with a host name or InetAddress and a port number. You can also specify a local InetAddress and port to which the socket will be bound. A ServerSocket class lets you listen on a port for incoming connection requests, creating a socket for each request. For example, the following program accepts input on a socket:

import java.net.*;
import java.io.*;

public class AcceptInput {
    public static final int PORT = 0xCAFE;

    public static void main(String[] args) 
        throws IOException
    {
        ServerSocket server = new ServerSocket(PORT);
        byte[] bytes = new byte[1024];
        for (;;) {
            try {
                System.out.println("---------------------");


                Socket sock = server.accept();
                InputStream in = sock.getInputStream();
                int len;
                while ((len = in.read(bytes)) > 0)
                    System.out.write(bytes, 0, len);
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

This program creates a ServerSocket and repeatedly accepts connections to it. The Socket obtained for each connection is queried for an input stream and the data from that socket is read from the stream and written to the standard output stream, printing whatever bytes it receives. A client that shipped its standard input to the server might look like this:

import java.net.*;
import java.io.*;

public class WriteOutput {
    public static void main(String[] args) 
        throws IOException
    {
        String host = args[0];
        Socket sock = new Socket(host, AcceptInput.PORT);
        OutputStream out = sock.getOutputStream();
        int ch;
        while ((ch = System.in.read()) != -1)
            out.write(ch);
        out.close();
    }
}

Once we have the actual Socket connection, I/O is performed, like all other I/O, using an appropriate input or output stream.

A URL object stores a URL, providing methods to examine and set its various parts (protocol, host, port number, and file). A URL object simply names a resource—you invoke openConnection to connect to the named resource. The openConnection method returns a URLConnection object that lets you get the header fields and content of the resource as input and output streams. The following program reads the contents of a URL:

import java.net.*;
import java.io.*;

public class ReadURL {
    public static void main(String[] args) {
        for (String url : args) {
            try {
                readURL(url);
            } catch (Exception e) {
                System.err.println(url + ":");
                e.printStackTrace();
            }
        }
    }

    private static void readURL(String name)
        throws MalformedURLException, IOException
    {
        URL url = new URL(name);
        URLConnection connect = url.openConnection();
        InputStream in = connect.getInputStream();
        byte[] bytes = new byte[1024];

        int len;        // number of bytes actually read
        while ((len = in.read(bytes)) >= 0)
            System.out.write(bytes, 0, len);
    }
}

The URLEncoder class lets you turn an ISO Latin-1 string (such as a user-typed query) into a form that can be included as part of a URL. ASCII letters and digits remain unchanged, the space character is converted to a +, and all other characters are represented by their lower 8 bits in hex preceded by a %.

The File.toURL method creates a file URL for the path specified by that File object.

You can create DatagramSocket objects for sockets that send and receive DatagramPacket objects, which contain an array of bytes. Datagrams are a connectionless packet delivery service, in which packets are individually addressed and routed and could be received in any order. With the MulticastSocket subclass of DatagramSocket, you can set up a socket that can send and receive packets to and from multiple addresses.

java.rmi — Remote Method Invocation

When you can download and run code on other systems, the face of distributed computing changes. The Java platform's Remote Method Invocation (RMI) gives you a way to create objects whose methods can be invoked from other virtual machines, including those running on completely different hosts. Because RMI is designed for communicating between Java virtual machines it can take advantage of the architecture's features and can operate in a natural fashion for programmers. RMI is contained in the package java.rmi and its subpackages, most notably the package java.rmi.server for RMI server implementations.

To use RMI you must first design one or more remote interfaces—interfaces whose methods can be invoked remotely. A remote interface extends the Remote interface, and its methods throw RemoteException in addition to any other exceptions. Here, for example, is a simple definition of a compute server interface that will accept Task objects for execution, returning the resulting Object:

import java.rmi.*;

public interface ComputeServer extends Remote {
    Object compute(Task task) throws RemoteException;
}

The Task interface is generic, allowing a ComputeServer to do any computation requested of it:

public interface Task extends java.io.Serializable {
    Object run();
}

Task itself is not a remote interface. Each ComputeServer object will run on a host and will be asked to execute tasks locally on its own host and return any results. (Traditionally, the application invoking a remote method is called the client of the invocation, and the application executing the method is called the server, although a client of one invocation may be the server of another.) Task extends Serializable because all local types passed to or returned from a remote method must be serializable.

Each method of a remote interface is required to throw RemoteException because any invocation of a remote method can have failures that must be signaled. Recovery from these failures is unlike recovery in local computation, where methods always arrive at their intended objects and either results are always returned or you clearly know that they were not returned.

When you invoke a remote method, network failures create new uncertainties—if the network fails after the request is transmitted from the client, the client doesn't know whether the request was received. The failure may have happened before the invocation reached the server, or it may have happened after it reached the server but before results could be returned. There is no way for the client to know which of these two cases actually happened. If the request is to withdraw money from your bank account, you would not want to simply retransmit the request—it might get there twice. Remote interfaces must be designed to allow clients to recover from such partial failures. Methods may be idempotent—meaning the method can safely be reinvoked—or some other recovery method may be provided for the interface, such as transactions that can be aborted when non-idempotent methods fail. The users of a remote object must recover from such failures, and the declared RemoteException helps them do so.

Here is a simple implementation of the ComputeServer interface:

import java.rmi.*;
import java.rmi.server.*;

public class ComputeServerImpl
    extends UnicastRemoteObject
    implements ComputeServer
{
    public ComputeServerImpl() throws RemoteException { }

    public Object compute(Task task) {
        return task.run();
    }

    public static void main(String[] args) 
        throws java.io.IOException
    {
        // use the default, restrictive security manager
        System.setSecurityManager(new RMISecurityManager());

        ComputeServer server = new ComputeServerImpl();
        Naming.rebind("ComputeServer", server);
        System.out.println("Ready to receive tasks");
    }
}

This code is also straightforward. When a compute invocation arrives from a client, ComputeServerImpl implements the ComputeServer interface by taking the Task object it is given and invoking its run method, returning the resulting Object. Each incoming request typically gets its own thread, so this compute server implementation could have many concurrently executing tasks for different clients. ComputeServerImpl extends UnicastRemoteObject, which provides references for single-server remote method invocation. UnicastRemoteObject, like most types needed only by servers, is defined in java.rmi.server. The ComputeServerImpl constructor declares that it throws RemoteException because it can be thrown by the (implicitly invoked) UnicastRemoteObject constructor when it registers the object with the RMI system.

Now comes the fun part. Clients can ask the server to perform any computation at all. Suppose, for example, that you want to compute π to some number of decimal places. You can have the compute server do this for you:

import java.math.BigDecimal;

public class Pi implements Task {
    private int decimals;

    /** Calculate Pi to a given number of decimal places */
    public Pi(int decimals) {
        this.decimals = decimals;
    }

    public Object run() {
        BigDecimal res = computePi();
        return res;
    }

    BigDecimal computePi() {
        // ...
    }
}

The Pi class implements the Task interface with a run method that returns a java.math.BigDecimal object containing the computed result. You then put the compiled Pi class someplace where it can be downloaded from a URL, just as an applet class would be. The URL from which to download the code will be set as a property for your client.

When you invoke the compute server's compute method, passing a Pi object, the server will need the Pi class. It will look at the URL that has been implicitly passed with the request, download the class, and run it in a secure sandbox. It will then invoke the Pi object's run method and return the result.

This ComputeServer example leverages the Java virtual machine's homogeneous computing model, in which all code means the same thing on all platforms, and its security model, in which downloaded code can be run securely.

Many environments can use the basic infrastructure just described. A compute farm that uses a large number of computers to render animation can use such a system to feed those computers images to be rendered, sound computations, and other tasks. This simple example needs some hardening to be used in other situations, especially when Task objects could not be trusted to be friendly. All you need is a Java virtual machine at both ends of the network.

UnicastRemoteObject references are for remote services that are started by the user or system. You can use java.rmi.activation.Activatable for references to remote objects that you want to be started automatically when they are first needed.

Because of the dangers inherent in running downloaded code, RMI requires that a security manager be installed. The RMISecurityManager class is a very conservative security manager that you can install to prevent unauthorized access to your system, or you can provide your own security manager.

Your server class may not be able to extend an RMI server class because your class must extend a different class. For example, an applet class must extend Applet and so cannot extend UnicastRemoteObject. You can create servers that do not extend UnicastRemoteObject by having your class's constructor invoke a static method:

public class SnazzyApplet extends Applet
    implements SnazzyRemote
{
    public SnazzyApplet() throws RemoteException {
        UnicastRemoteObject.exportObject(this);
    }
    // ... implement SnazzyRemote and Applet methods ...
}

Classes are downloaded from client to server (or server to client) only if they are needed. Classes will often be known on both sides. For example, BigDecimal is part of the core, so both the client and the server already know about it and it will not be downloaded. User-defined classes are treated in the same way—if both the client and server have a class installed, it will not be downloaded across the network.

Arguments and return values of remote methods are handled somewhat differently from those of local methods. RMI passes arguments and return values by using object serialization (see page 549). When a remote reference is passed as an argument or return value, the receiver will get a reference to the same remote object that was passed. This is how local references act in local methods—an object reference refers to the same object in both the invoking code and the invoked method. Primitive types, too, are passed in the same way locally and remotely; the receiver gets a copy of the value.

References to local objects must be passed differently. Local objects are not designed to deal with partial failures, so it is not possible to pass across the network a remote reference to a local object. Local objects are instead passed by a deep copy made by serialization. Any remote references contained within the object or in any part of the graph of objects it denotes will be passed as described earlier. All other parts of the graph will be serialized on the sender's system and deserialized on the receiver's. Changes made on one side will not be visible to the other side, because each side has its own local copy of the object.

The RMI registry provides a simple naming system to store remote references for bootstrapping your clients. This is not a full naming system, but it will let you store objects that register or find top-level services. The registry is accessed via the Naming class.

Server objects are governed by a “best effort” distributed garbage collector. When no outstanding references to a remote object exist, that object can be collected. This is similar in principle to garbage collection for local objects, but the failures of distributed computing make surety impossible. If a client hasn't been in contact for a long time, it is presumed to have gone away without notifying the server (possibly the system crashed). If a long-lived network failure is actually at fault, the client may find that the server has been garbage-collected when the network reconnects. Every reasonable effort is made to preclude this possibility. A server can ensure that it will never be garbage-collected by simply holding on to a remote reference to itself, thus ensuring that at least one remote reference will keep it alive. This reference can be dropped when the server decides that it no longer must be forced to be alive.

RMI is explicitly designed to take advantage of having both client and server in the Java programming language. This gives it a form that is simple and direct for people who know the language. You can, of course, implement any server methods you like as native methods. Native methods can help you use RMI as a bridge to existing native code, such as in two- and three-tier systems.

The subpackage java.rmi.activation provides for activatable servers, which will be started when they receive messages if they are not already running. Multiple servers can be put in the same activation group, and will then be run in the same virtual machine.

java.security and Related Packages — Security Tools

The security architecture that was introduced in Chapter 23 is quite extensive and incorporates a range of mechanisms for encryption, authorization, authentication, and so forth. These mechanisms are spread across a number of packages.

The package java.security contains several useful tools for security-related functions: digital signatures, message digests, key management, and cryptographic keys. Subpackages define abstractions for certificates (java.security.cert), RSA and DSA keys (java.security.interfaces), and key and algorithm parameter specifications (java.security.spec).

The javax.security subpackages complement these tools with a full authentication and authorization framework (javax.security.auth and its subpackages), including support for the Simple Authentication and Security Layer (SASL) as defined by RFC 2222 (the javax.security.sasl package). The authorization component allows specification of access controls based on code location, code signers, and code executors (subjects), using common protocols such as Kerberos and X500.

The javax.crypto package and subpackages (interfaces and spec) provide rich mechanisms for cryptography, including encryption with various kinds of ciphers, MAC generation, and key creation and agreement.

The org.ietf.jgss package provides a framework that helps you use security services such as authentication, data integrity, and data confidentiality from a variety of underlying security mechanisms. The security mechanisms an application can choose are identified with unique object identifiers. For example, the Kerberos v5 GSS-API mechanism has the object identifier 1.2.840.113554.1.2.2. This mechanism is available through the default instance of the GSSManager class.

Because there are many ways to approach things like cryptography and authentication, and there will be many more in the future, the security architecture provides abstractions of security interactions. Implementations of the abstractions are supplied by providers. Each platform has one or more providers. The java.security.Security utility class provides methods to find out which providers are available. Providers can interoperate through the provided abstractions.

Much more information on these packages, and on security in general in the virtual machine, is in Inside Java 2 Platform Security, Second Edition.

java.sql — Relational Database Access

The package java.sql provides the Java Database Connectivity (JDBC) package for using relational databases. These classes and methods can be implemented directly by your database vendor or through the industry-standard Open Database Connectivity (ODBC) interface. JDBC is, in effect, a mapping of ODBC. The JDBC package and other issues about relational databases are covered in JDBC API Tutorial and Reference, Third Edition.

Utility Subpackages

Some of the utility classes in java.util are not independent classes but groups of related classes that together provide a particular functionality. These classes are themselves grouped into subpackages within java.util.[1]

Concurrency Utilities — java.util.concurrent

The package java.util.concurrent, together with its subpackages provides a range of utilities for writing efficient multithreaded applications. These utilities expand the in-built synchronization facilities of the Java programming language to allow building concurrent applications that would not otherwise be possible with synchronized code, and to simplify common synchronization tasks that would otherwise be tedious and error-prone to write using the language facilities. The utilities provided can be divided into five categories:

  • Concurrent collections—. These were described in Chapter 21.

  • Synchronizers—. A group of utility classes that simplify common synchronization tasks (discussed below).

  • Executor framework—. A framework for asynchronous task execution, including a flexible, high-performance thread pool implementation.

  • Locks and Conditions—. Classes that provide locking and waiting capabilities that go beyond those of the built-in monitor capabilities.

  • Atomic variables—. A set of classes that allow safe expression of lock-free and wait-free algorithms within an application.

There are four synchronizer classes:

  • Semaphore—. A counting semaphore. Useful for many situations in which access to a resource must be controlled. To use the resource a thread must acquire a (conceptual) permit, or token, from the semaphore. If none is available then the thread blocks until one is. When finished with the resource the thread releases the permit back to the semaphore to allow other threads to proceed. A counting semaphore can hold an arbitrary number of permits; a binary semaphore is a semaphore with only one permit.

  • CountDownLatch—. A utility for blocking until a given number of events have occurred or until certain conditions hold. The latch is created with a given number of events to expect. Each thread that triggers an event or sets a condition calls the countDown method which decrements the initial count. A thread that calls the await method will block until the latch has counted down to zero.

  • CyclicBarrier—. A utility that forces all threads using the barrier to wait until all those threads are ready to pass the barrier. This is useful for multi-phase algorithms in which all threads must complete a given phase before any threads commence the next phase.

  • Exchanger—. A simple utility that allows two threads to exchange data. The first thread to arrive at the exchanger waits until the other arrives, they then exchange data and proceed.

An Executor knows how to execute a task—which is represented by a Runnable object—and replaces the direct creation of new threads within an application. Depending on the implementation used, the Executor may execute the task in the current thread, submit the task to a thread pool for later execution, or perhaps create a new thread to execute the task. The Executor abstracts all the details of thread creation and management and allows the problem of executing tasks to be separated from the problem of generating tasks. An ExecutorService expands on the basic executor to provide lifecycle management—such as shutting down an executor. Particular implementations of ExecutorService provide thread pools (ThreadPoolExecutor) and permit the scheduling of tasks in the future (ScheduledThreadPoolExecutor).

The Callable interface defines a task that can return a result (unlike a Runnable). A Future represents a computation—such as that in a Callable—that may not yet have completed or even begun. You can submit a Future to an Executor (using the concrete FutureTask class) knowing that at some time in the future the result of the computation will be available. You can use the Future to ask whether the task has completed or to block until the task completes and the result is available.

The java.util.concurrent.locks subpackage defines the Lock and Condition interfaces and the ReentrantLock implementation. Lock abstracts the functionality of locking, as implied in the use of synchronized blocks and methods, to allow more flexible locking. A Lock can be locked in one method and unlocked in a different one—something that is needed in some concurrent traversal algorithms, and which is impossible to do with synchronized blocks or methods. In addition, the methods of Lock allow you to acquire the lock only if it is available—that is, you don't block trying to acquire the lock—or to stop trying to acquire the lock if interrupted or if a certain time has elapsed.

A Condition abstracts the functionality of the Object monitor methods wait, notify, and notifyAll into a distinct interface with methods await, signal, and signalAll. Condition objects are used with Lock objects the same way that wait/notify are used with monitors. The advantage is that while there is only a single wait-set per object, a Lock can have as many associated Condition objects as you need. The ReentrantLock class is one useful implementation of Lock that gives you Condition objects that are functionally equivalent to synchronized methods and blocks, plus the use of the monitor methods.

The package also contains the ReadWriteLock interface—and an implementation—for a lock that allows for both exclusive use and shared use—informally, only one writer may hold the lock (exclusive) but arbitrarily many readers can hold the lock (shared).

The java.util.concurrent.atomic package provides classes that represents values (int, long, references, and arrays of these values) that can be manipulated atomically. These classes provide operations that without the use of locks or in-built synchronization can, for example, get, set, increment, or decrement an integer. Atomic variables are used in the implementation of high-performance concurrent algorithms. For each basic atomic variable class, such as AtomicInteger, there is a corresponding atomic field updater class, such as AtomicIntegerFieldUpdater, that allows you to access a given field of an object atomically. These classes also provide the compareAndSet operation that is the fundamental operation in most lock-free and wait-free concurrent algorithms. It will atomically set a variable to a new value only if the variable currently holds an expected value.

Archive Files — java.util.jar

The java.util.jar package provides classes for reading and writing the JAR (Java ARchive) file format, which is based on the standard ZIP file format with an optional manifest file. JAR files can be used to distribute the classes and resources of a Package as a single unit. The manifest stores information about the JAR file contents and provides the specification information for the Package contained therein—as we discussed on page 477.

Archive files define a format for storing multiple files within a single file, and allow for the compression of those original file contents. A full description of archive files, particularly the JAR format, is beyond the scope of this book. For illustration we briefly describe each of the classes within the java.util.jar package:

  • Attributes—. maps Manifest attribute names to associated string values.

  • Attributes. Name—represents an attribute's name. The main function of this class is to define static Attributes.Name objects for each attribute that a manifest may have. For example, the object corresponding to the “Manifest-Version” attribute of a manifest is stored in the static field Attributes.Name.MANIFEST_VERSION.

  • JarEntry—. represents a JAR file entry.

  • JarFile—. represents an actual JAR file and allows that JAR file to be read or written.

  • JarInputStream—. reads a JAR file. Methods exist that read each entry of the JAR file into a new JarEntry object.

  • JarOutputStream—. writes a JAR file. Methods exist that take a JarEntry object that is written to the JAR file.

  • Manifest—. maintains manifest entry names and their associated attributes.

A JarFile represents an actual JAR file and allows its contents to be read or written with the appropriate streams. A JAR file consists of a manifest and a number of JAR entries that can be read or written individually. The manifest contains all the attributes of the JAR file and all the attributes of the entries in the JAR file. The manifest is decoded with the Manifest and Attributes classes. Each JarEntry contains the per-entry attributes extracted from the manifest.

Most users never need to use the classes within java.util.jar. JAR files can be created via tools supplied as part of your development environment and are read automatically by the class loader within the virtual machine when needed.

ZIP Files — java.util.zip

The java.util.zip package provides classes for reading and writing standard ZIP and GZIP file formats. We mention it only for completeness, as it predates the newer JAR file format and forms its basis.

  • ZipFile—. represents a ZIP or GZIP format file.

  • ZipEntry—. represents an entry in a ZIP or GZIP format file.

  • ZipInputStream—. reads ZIP file format.

  • ZipOutputStream—. writes ZIP file format.

  • GZIPInputStream—. reads GZIP file format.

  • GZIPOutputStream—. writes GZIP file format.

  • Deflater—. provides general support for using ZLIB compression.

  • DeflaterOutputStream—. writes using ZLIB compression

  • Inflater—. provides general support for using ZLIB decompression.

  • InflaterInputStream—. reads ZLIB compressed data.

  • CheckedInputStream—. reads a stream, creating a checksum of the data.

  • CheckedOutputStream—. writes a stream, creating a checksum of the data.

  • CRC32—. computes a checksum using the CRC-32 algorithm.

  • Adler32—. computes a checksum using the Adler-32 algorithm.

javax.* — Standard Extensions

Standard extensions are packages or collections of packages that can be downloaded to extend the capabilities of a particular virtual machine. They will usually have names starting with javax, although future exceptions may be made. Conversely, packages with javax in the name may become part of the main set of packages over time. For example, the javax.swing and javax.accessibility packages are part of the main set. The name indicates that they were at first not part of the main set, but integrated later.

Standard extensions are a mechanism that allows growth in the capabilities of the platform without further extensions to the core packages required of all virtual machines. New standard extensions can be defined and made available, but only installed where they are needed. Several standard extensions are defined, and more are on the way. Listing them all is far outside the scope of this book—you can find more information on the Web, especially at http://java.sun.com.

javax.accessibility — Accessibility for GUIs

Graphical user interfaces traditionally assume certain kinds of abilities on the part of the user, such as the ability to use a mouse or keyboard. These assumptions are a problem for some people. The javax.accessiblity interfaces and classes provide a way to write interfaces that can use assistive technologies for input and output, allowing people with different abilities to use the same interfaces. If an application fully supports the accessibility API, then it should be compatible with, and friendly toward, assistive technologies such as screen readers and magnifiers.

javax.naming — Directory and Naming Services

This package defines the naming operations of the Java Naming and Directory Interface (JNDI), with the subpackage javax.naming.directory, defining the directory operations. These are designed to be independent of any specific naming or directory service implementation. Thus a variety of services—new, emerging, and already deployed ones—can be accessed in a common way.

A context, represented by the Context interface, consists of a set of name-to-object bindings. Context is the core interface for looking up, binding, unbinding, and renaming objects, and for creating and destroying subcontexts. lookup is the most commonly used operation. You supply lookup the name of the object you want to look up, and it returns the object bound to that name. For example, the following code fragment looks up a printer and sends a document to the printer object to be printed:

Printer printer = (Printer) ctx.lookup("Duplex");
printer.print(report);

Every naming method in the Context interface has two overloads: one that accepts a Name argument and one that accepts a string name. Name is an interface that represents a generic name—an ordered sequence of zero or more components. For these methods, you can use Name to represent a composite name (CompositeName) so that you can use a name that spans multiple namespaces.

The overloads that accept Name arguments are useful for applications that need to manipulate names: composing them, comparing components, and so on. The overloads that accept string names are likely to be more useful for simple applications, such as those that simply read in a name and look up the corresponding object.

The Binding class represents a name-to-object binding. It is a tuple containing the name of the bound object, the name of the object's class, and the object itself. The Binding class is actually a subclass of NameClassPair, which consists simply of the object's name and the object's class name. The NameClassPair is useful when you only want information about the object's class and do not want to pay the extra cost of getting the object.

Objects are stored in naming and directory services in different ways. If an object store supports storing objects it might store that object in its serialized form. However, some naming and directory services do not support the storing of such objects. Furthermore, for some objects in the directory, Java programs are just one group of applications that access them. In this case, a serialized object might not be the most appropriate representation. JNDI defines a Reference that contains information on how to construct a copy of the object. JNDI will attempt to turn references looked up from the directory into the objects they represent so that JNDI clients have the illusion that what is stored in the directory are objects.

In JNDI, all naming and directory operations are performed relative to a context—there are no absolute roots. Therefore, JNDI defines an InitialContext class that provides a starting point for naming and directory operations. Once you have an initial context, you can use it to look up other contexts and objects.

The DirContext interface represents a directory context. It defines methods for examining and updating attributes associated with a directory object, or directory entry as it is sometimes called. You use getAttributes to retrieve the attributes associated with a directory object (for which you supply the name). You can add, replace, or remove attributes and/or attribute values with the modifyAttributes method.

DirContext also behaves as a naming context by extending the Context interface. This means that any directory object can also provide a naming context. For example, the directory object for a person might contain the attributes of that person, and also provide a context for naming objects relative to that person such as printers and home directory.

DirContext contains methods for performing content-based searching of the directory. In the simplest and most common form of usage, the application specifies a set of attributes—possibly with specific values—to match, and submits this attribute set to the search method. Other overloads of search support more sophisticated search filters.

The subpackage javax.naming.event supports event notification for directory and naming services. Events include adding or removing objects, as well as events signifying changes in the stored objects themselves.

The subpackage javax.naming.spi defines the Service Provider Interface (SPI) which allows for dynamically plugging in support for using JNDI.

javax.sound — Sound Manipulation

The javax.sound package consists only of subpackages. javax.sound.midi provides interfaces for reading, writing, sequencing, and synthesizing data that conforms to the Musical Instrument Digital Interface (MIDI) format. javax.sound.sampled provides classes and interfaces for capturing, processing, and playing back digital (sampled) audio data. Each of these has a SPI subpackage to support the dynamic addition of sound services.

javax.swing — Swing GUI Components

The Swing components are a rich set of graphical user-interface controls. They are written to look and behave for the user identically on all systems as far as possible. This is in contrast to the AWT components which rely on the native GUI components. An AWT button will look like a Windows button on a Windows machine, a Macintosh button on a Macintosh computer, and so forth—its interaction with the program is the same on all platforms, but the user will see the native look and feel. A Swing component can have the same look on all platforms—its code is written in the Java programming language. The look and feel is “pluggable”—you or the user can use one of the standard look-and-feels or invent one. Swing components are also give you more control over the look and behavior of the system. You only occasionally need such control, but it is nice to have it when you do need it.

The Swing components use the same event model as AWT and JavaBeans components, although the components do define some new events.

Several subpackages define interface objects, tools for defining a custom pluggable look-and-feel, support HTML and text editing, and support some of the more complex components, such as tree displays and tables.

org.omg.CORBACORBA APIs

The package org.omg.CORBA, its various subpackages and other org.omg subpackages (such as CosNaming) provide the mapping of the OMG CORBA APIs and services to the Java programming language. (The package names are different from the standard core package names because they are defined by the Object Management Group and incorporated into the core package set.) CORBA is a way to send messages between processes that are not necessarily written in the same programming language. This is distinct from RMI, which communicates between programs written, at least in part, in the Java programming language (we use the phrase “at least in part” because RMI programs can include native code).

 

Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far the universe is winning.

 
 --Rich Cook


[1] For pragmatic reasons the collections classes had to be defined at the top level of java.util, rather than in a subpackage, because of the existing legacy collections.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.181.186