Externalities are an issue for a replicated distributed application. Consistency among the replicas is insured as long as each deterministic replica receives that same input. Since externalities are machine-specific, replicas of an externality could deliver different values to each replica of the shared application. Our approach to dealing with this is to replace each externality with a proxy that communicates with a central instance of the externality which delivers the same value to each replica.
As a rule, an externality object will access resources on its host machine via a native method, which is a platform-specific implementation of a method to which the platform-independent Java Virtual Machine passes control. Some native methods are private and are wrapped by public Java methods that we can override in a platform-independent manner. However, public native methods are a problem for our proxy scheme, because we cannot override them with a platform-independent implementation in a proxy of the externality.
This document enumerates the externality classes in Java. Each
class name is followed with a brief description of the class and what makes
it an externality. The class's public native methods are listed.
Note that not all of these public native methods are related to accessing
the problematic externality of the class (e.g., shared replicas calling
gc() (garbage collect) of Runtime will not cause a problem).
File encapsulates platform-specific information for path and file separators,
as well as a representation of files on the local file system. You can
query this object for access permissions, file type, making a directory,
etc.
Public native methods:
FileInputStream reads a file that resides on a storage device.
Public native methods:
FileOutputStream writes to a file that resides on a storage device.
Public native methods:
A RandomAccessFile access a file that resides on a storage device that
can be written to or read from in a random fashion.
Public native methods:
FileDescriptor represents an open file or socket. Applications
should not create their own FileDescriptor objects, so this externality
should not need to be proxied.
Public native methods:
Runtime provides information about the runtime environment executing
the Java code, such as the amount of free memory.
Public native methods:
Process objects are returned by exec() calls on Runtime and provide
access to a child process's input and output streams. Process is
an abstract class and is therefore not inherently an externality, but subclasses
of it are.
System accesses properties, standard input and output streams
(stdin, stdout, and stderr) and the current time of the system.
Public native methods:
InetAddress provides queries related to internet host addresses including
the local host address. InetAddress itself has no native methods,
but contains a platform-specific subclass of InetAddressImpl, which has
native methods.
These classes provide input and output to a network. These classes
do not contain native methods themselves, but use platform-specific subclasses
of the abstract SocketImpl and DatagramSocketImpl classes.
Properties is a set of name-value String pairs that an application can
be used as input and output by an application. Properties is
not an externality, but the objects used to load and save Properties are,
typically FileInputStream and FileOutputStream. A commonly used set
of Properties are accessed via System.getProperty. System is an externality.
Random is a random number generator. So long as all replicas of
a random object have the same seed value, the values they deliver will
be consistent. If a seed is not specified, Random uses the system
time as the seed. The system time is an externality.
The date for newly created date objects needs to be a common date for
all replicas. Date uses the current system time to create a date
object. The system time is an externality.