Package java.lang.isolate

Provides for the creation and management of isolated applications.

See:
          Description

Interface Summary
IsolateMessageDispatcher.Listener A listener interface for receiving messages and exceptions from an IsolateMessageDispatcher's managed links.
 

Class Summary
Isolate The Isolate class provides the means of creating and managing isolated computations and arranging for their communication with each other.
IsolateEvent Isolate events represent state changes in an isolate life cycle.
IsolateEvent.ExitReason Provides information about how an isolate became terminated.
IsolateEvent.Type Define the types of an IsolateEvent that can be generated.
IsolateMessage An IsolateMessage wraps the various types that can be sent through a Link, or on an isolate start invocation or for redirecting an isolate's "standard" I/O.
IsolateMessageDispatcher Receives and dispatches messages to listeners.
IsolateMessageVisitor An abstract utility class used to process an IsolateMessage containing arbitrary data via IsolateMessage.acceptVisitor.
IsolatePermission This class represents access to or creation of an isolate or link.
Link A Link supports communication between isolates.
 

Exception Summary
ClosedLinkException An exception thrown when an operation is performed on a closed link.
IsolateStartupException An exception thrown when the implementation is unable to start execution of a new isolate due to an error or exceptional condition in the setup or bootstrap code for the new isolate (i.e., before the application starts).
LinkSerializationException An exception thrown as the result of one of a number of underlying serialization-related exceptions.
 

Error Summary
IsolateResourceError IsolateResourceError is thrown when the resource requirements required for an action cannot be fulfilled.
 

Package java.lang.isolate Description

Provides for the creation and management of isolated applications. Using the java.lang.isolate classes, users can create isolated environments for running untrusted code, application extensions, or other code that should be isolated.

JSR-121: Java Application Isolation API Specification

1. Introduction

JSR-121 specifies a new fundamental facility for supporting multiple applications in the Java programming language. The java.lang.isolate package provides programming-level support for creating, starting, exiting, managing, and communicating with otherwise separate Java programs.

The Java Application Isolation Specification ("Isolate API") is in two parts. This document contains the rationale and overview. The surrounding javadoc contains specific details for the classes, methods, and semantics of the API organized by class.

The only fundamental requirement of JSR-121 that cannot be stated in the API specification is that henceforth, all static methods and fields (as well as associated JVM and JNI facilities) that are worded to have per-program scope are to be interpreted as acting on a per-isolate basis unless explicitly stated otherwise.

2. Rationale

1. The Role of Isolates

The choice of the uncommon (but accurate) noun form of Isolate for the main class avoids ambiguities and misleading connotations of more common terms, such as "process" and "task." It also emphasizes the basic property that isolates do not and cannot share access to objects. For example, the static variables in each isolate are unique to that isolate.

Informally, isolates are a construct midway between threads and JVMs. Like threads, they can be used to initiate concurrent execution. Like JVMs, they cause execution of a "main" method of a given class to proceed within its own system-level context, independently of any other Java programs that may be running. Thus, isolates differ from threads by guaranteeing lack of interference due to sharing statics or per-application run-time objects (such as the AWT thread and shutdown hooks), and they differ from JVMs by providing an API to create, start, terminate, monitor, and communicate with these independent activities. The Isolate API is intended to provide a minimal yet complete interface for the many applications and frameworks that might take advantage of such a facility.

The following diagram shows the relationships between threads, isolates, and and the "JVM".

jvms and isolates

The Isolate API is intended to be implementable in at least three very different styles:

  1. All-in-one. A JVM is constructed within a single operating system (or hardware-level) process but implements isolation guarantees directly in the JVM.
  2. One-to-One. A JVM manages a set of OS-level processes, one per isolate.
  3. Clustered. Isolates may reside on different physical machines within a cluster that provides a consistent view on the external environment for all isolates. (For example, all isolates see the same file system, access the same network services, use the same network addresses, etc.)
The term aggregate in the context of isolates will be used to refer to the set of isolates sharing a common ancestor. Thus with the styles list above, an aggregate involves only one OS or hardware level process for an all-in-one implementation while for the other two styles, multiple isolates belonging to an aggregate implies multiple processes. This specification defines no mechanism for communication between separate aggregates.

JSR-121 is a J2SE, not a J2ME specification. However, it is designed to allow subsets to cleanly accommodate differences in IO and related types across J2SE and the various J2ME profiles. A proposed subset list defines current thinking about J2ME requirements and this list is present as notations in individual class and method javadoc.

While we expect isolates to be used across a wide range of systems, we have specifically focussed on support of the following usage scenarios in which, to maximize performance, reliability, controllability, and/or security, each independent component should be run independently of all others:

  1. Independent applications. For example, a system may choose to initialize a JVM upon boot or login time and arrange that the "java" command create a new isolate to run the given application.
  2. Containment Frameworks. Layered frameworks that execute "*lets" (Servlets, Applets, etc.) may provide options to run them as isolates.
  3. Server Forks. A network service may choose to spawn handlers servicing new clients as isolates.
  4. Fault tolerance. A system may choose to run multiple versions or redundant copies of essential services in separate isolates to enhance reliability.
  5. Clustered Execution. Analogs of "Beowulf clusters" and related frameworks arrange parallel execution of computationally intensive programs across the nodes of a cluster.
Each of these target use cases (as well as several variants and extensions) introduces different requirements and constraints. However, it is not the goal of JSR-121 to actually construct any of these frameworks, but only to make them possible, while maintaining a small, easy-to-learn API that fits well with other features of the language. Similarly, JSR-121 does not address issues related to but beyond the scope of simple isolation, including resource controls.

2. Isolate Lifecycle

The API for constructing isolates must accommodate all of the ways in which users can execute "Java programs." This entails supplying the class name, class path, arguments, and so on. Perhaps ideally, all of these would be encapsulated in a common structure, but to maintain compatibility with existing code and practice, the API dealing with creating and starting isolates supports a diverse collection of parameters, separately dealing with Properties, IO settings, etc. However, we also introduce a simple uniform mechanism to support non-historically-bound settings. The isolate context based on the java.util.prefs.Preferences API. JSR-121 does not specify how an isolate context is to be used but does predefine some name-value pairs and how they are to be interpreted by JVMs. We expect that some layered frameworks will continue to use yet other mechanisms (such as JNDI) within newly created isolates to establish other aspects of execution context.

The choice of defaults for the various creation parameters is intended to simplify the most common usages while still making it possible to provide the fine degree of control required in containment frameworks.

All of the isolates running under a given JVM share a few minimal, immutable Properties settings, including user identity and initial security policy. They also implicitly share any underlying system context; for example, all isolates must share the same view of the current file system. Even here though, there is a potential ambiguity about whether class files that have been updated since the instantiation of a JVM but before construction of a given isolate will be freshly loaded for that isolate. This is resolved by a predefined isolate context setting that controls whether updated class files must (as opposed to may) be loaded with the new application.

As with threads, the Isolate API separates the points of creating an isolate (establishing its existence without running any application code, not even static initializers) and starting it (causing it to run application code). This provides flexibility for both users and implementors, at the cost of some minor uncertainties. We do not specify whether the act of creating an isolate will consume resources or execute system-level code; all of this may be deferred to "start" time. Thus, the set of exceptions that may be thrown at each point overlaps.

Like a Java program, but unlike a thread, an isolate may be terminated either "normally" or "abruptly." Usage and semantics precisely parallel that for System.exit and System.halt. An explicit termination event is available to signal the point at which no user code will execute in the associated isolate ever again.

No special API is provided to start or stop a JVM, as opposed to an isolate. Note that a JVM that has no isolates cannot execute any bytecodes, so is not very useful. We expect that the most common implementation of shell-level "java" commands will use system-specific techniques to establish a "primordial" isolate that may in turn spawn other isolates. A JVM itself may terminate when all of its isolates do.

3. Communication

The Link class and its helper classes provide a basic, low-level communication medium across isolates. Minimally, the Link subclasses can be used to establish other communication mechanisms. To maintain isolation, Links provide only "data" copying facilities; normal Java objects cannot be shared by passing them. However, to minimally support interaction, links may be used to pass the "special" types Isolate and Link, as well as a set of IO-related types. The existence of these "special" types introduces some slight irregularity, as well as some J2SE/J2ME differences, but this is a consequence of other choices made for supporting IO across different packages and frameworks. It would have been beyond the scope of JSR-121 to force all relevant APIs and specs to be reworked solely for the sake of making a slightly more elegant link API. Instead, all of the expected variation is encapsulated in the IsolateMessage class that controls which types can be sent and received across links.

Like isolates, links provide a simple, reliable, efficient basis for layered frameworks. For example, RMI or CORBA should be able to use links as primitives for inter-isolate connections (though JSR-121 does not specify whether or how this happens).

Of course, any current inter-JVM communication mechanism (networking, RMI, file systems or shared memory) will continue to work for communication between isolates.

The primary low-level design goal of the Isolation API is to support strict separation between multiple computations within a single physical virtual machine. So why does it provide its own inter-Isolate communication model? Inter-Isolate communication is required to support one of the key higher-level design goals : the partitioning of logically monolithic applications to provide improved security and robustness in the presence of untrusted or unreliable code. Many current Java APIs and application frameworks (Servlets, EJB, Applets, Agent Services etc.) follow a container/manager model where the container itself can be assumed to be both trusted and reliable but where the same assumption cannot be made about the contained components. These APIs and frameworks would clearly benefit from isolation: the container may be isolated from its containees and those containees may be isolated from each other, ensuring that local policy violations and failures cannot propagate globally.

This is a desirable property, but not at any cost. Most, if not all, container frameworks rely on communication of some sort between the container and it's containees and in some cases between the containees themselves. In a non-Isolate implementation this communication would typically be implemented via a combination of local method invocations and state shared amongst container and containees. Neither of these mechanisms are available in an Isolate-based implementation. Replacing them with existing forms of inter-process communication (via RMI, sockets or files) would bring with it communication overheads many orders of magnitude greater than those of non-Isolate implementations.

The Isolate Link API eliminates this communication overhead by allowing applications to open up efficient communication pinholes between their Isolated components in controlled way. The performance gains over traditional IPC lie in four areas,

These gains are difficult or impossible to achieve using existing Java IPC mechanisms.

The particular form taken by the Link API is partly dictated by the need to support the underlying communication mechanisms just mentioned, but also by two other constraints.

First, the desire not to have to specify or constrain inter-Isolate communication management or topology. The controlled ability to pass Links and Isolate references between Isolates provides the basis for implementing arbitrary communication policies and structures at the application level with minimal cost and complexity in the Isolate API itself. Given the goal of supporting the partitioning of arbitrary logically monolithic applications, this layering flexibility is essential.

Second, the desire not to have to invent a new, or depend on an existing but J2SE-only, naming scheme for Isolates. The API supports the creation of Links only where references to the participating Isolates are held by the Link creator. Those references can be obtained only by the creator of the participating Isolates or where the Link creator has been passed them across some pre-existing Link.

4. Monitoring and Management

The Isolate API does not enforce or even encourage any particular management style or topology of control across isolates. The only special relationship that a "parent" isolate has with a newly created "child" isolate is that the parent establishes the child's initial context. In all other respects, the parent and child are oblivious to each other unless programmers specifically arrange monitoring or communication between them.

Assuming that it has a handle to it, any isolate can register to receive "lifecycle" events from any other isolate. JSR-121 predefines only three events: starting (issued when the isolate's initial application-level thread begins execution), exiting (issued when the isolate first begins its shutdown process), and terminated (issued upon completion of isolate shutdown). A link created for event handling is used to receive these events, and IsolateMessageDispatcher can be optionally used to simplify listening for events from multiple isolates.

Similarly, assuming that it has both a handle and appropriate permissions, one isolate may cause another to exit or halt. The effects of termination are precisely the same as if they were invoked from within the target isolate.

JSR-121 does not explicitly provide any other kinds of monitoring events, controls, or grouping constructs, but the supplied classes and methods can be used to create a wide range of framework-specific management regimes, including those tied to external monitoring APIs such as JMX.

5. Security

JSR-121 introduces few security concerns. The basic functionality of the Isolate class is access-checked via a new IsolatePermission class. Permissions are checked during the acts of creating Isolate instances, invoking exit or halt, getting the current isolate context, sending or receiving an object on a link, and passing a link to a new isolate via start. In the default security policy all permissions except for retrieving the current isolate context are denied. Of the isolate-related permissions, users and framework developers should pay special attention to the "create" permission. The "create" permission lets the creator define the security policy of the new isolate, allowing it to circumvent any existing policy.

Beyond these concerns, security relies on the combination of guarantees that isolates cannot share references to objects, along with a capability-style scheme for helping to ensure that handles to other isolates can easily be confined to objects serving as managers.

Because all isolates view a common file system, all isolates by default rely on common default policy files.

6. JNI

JSR-121 does not strictly guarantee full isolation in the presence of native code. Libraries which use the Java Native Interface (JNI) are impacted in two ways with respect to isolation: fault isolation and OS-level state isolation.

The degree of fault isolation with respect to JNI code is treated as a quality of implementation property. Some JVM implementations may guarantee that faults in native code running in one isolate cannot affect others but some implementations may not. Currently, JNI libraries are not fault isolated from the core JVM runtime, so there should be no new issues introduced.

JNI libraries which modify OS process state (e.g., the current working directory, process-level resource limits, etc.) may find their changes isolated or may have them be aggregate-wide.

JNI libraries which do not fault and do not access OS-level services should continue to function normally with respect to isolation.

The java.lang.isolate.jni-isolation preference defined in an isolate's "context" (see Isolate.currentIsolateContext) will indicate if JNI code is isolated or not.

Acknowledgements

The following people took part in the effort to create, develop and deliver this API set to the Java community:

Alan Bateman, Josh Bloch, Grzegorz Czajkowski, Laurent Daynes, Dat Doan, Peter Donald, Gary Ellison, Bill Foote, Steve Goldman, Stephen Hahn, Graham Hamilton, Richard Houldsworth, Beth Hutchison, Jens Jensen, Peter Jones, Hideya Kawahara, David Katleman, Peter Kessler, Norbert Kuck, Doug Lea, Yoevita Liem, Tim Lindholm, Michey Mehta, Hans Muller, Jeff Nisewanger, Barbara O'Connor, Gary Pennington, Bill Pugh, Sanjay Radia, Mark Reinhold, Ken Russell, Miles Sabin, Bill Shannon, Glenn Skinner, Jenny Soper, Pete Soper, Tim Stack, Pat Tullmann, David Unitis, Glenn Vanderburg, Jan Vitek, Matthew Webster, Ann Wollrath, and Kumanan Yogaratnam.