A configurable Java(TM) Remote Method Invocation (Java RMI) activation system daemon implementation. Phoenix is a configurable alternative to `rmid`; it implements and supports all of the same activation interfaces and semantics as `rmid`, but it also implements and supports {@linkplain net.jini.security network security}. Like `rmid`, Phoenix also provides a simple command line interface for stopping an activation system daemon on the same host.

## Starting Phoenix

Phoenix can be started by command line, or it can be launched by the {@linkplain org.apache.river.start.ServiceStarter}. In either case, its configuration options must be specified as described in Phoenix Configuration.

1. Starting Phoenix by command line

   The standard command line for running Phoenix is:

       java [options] -jar install_dir/lib/phoenix.jar configOptions

   where options are standard options for the `java` command, install_dir is the directory where the Apache River release is installed, and configOptions are the options (typically starting with a filename or URL) of a Phoenix configuration.

   Phoenix has code that must be downloadable to clients, so one of the options should set the `java.rmi.server.codebase` system property to a codebase path (space-separated list of URLS) that serves up install_dir`/lib-dl/phoenix-dl.jar` and install_dir`/lib-dl/jsk-dl.jar` (in that order). Phoenix also runs with a security manager, so one of the options should set the `java.security.policy` system property to a security policy file. The Phoenix configuration must supply at least a `persistenceDirectory` entry for the component named `org.apache.river.phoenix`.

2. Starting Phoenix via Service Starter

   Phoenix supports being started via a {@link org.apache.river.start.NonActivatableServiceDescriptor}. An example service descriptor for starting Phoenix is:

       new NonActivatableServiceDescriptor(
           codebase,
           policy,
           "install_dir/lib/phoenix.jar",    // classpath
           "org.apache.river.phoenix.PhoenixStarter",  // implClassName
           serverConfigArgs)

   where codebase is the codebase path, policy is the name of the security policy file, install_dir is the directory where the Apache River release is installed, install_dir`/lib/phoenix.jar` is the class path for Phoenix, `org.apache.river.phoenix.PhoenixStarter` is the class name of the instance to construct to start Phoenix, and serverConfigArgs are the options (typically starting with a filename or URL) of a Phoenix configuration.

   Phoenix has code that must be downloadable to clients, so the codebase path specified by codebase should be two URLs that serve up install_dir`/lib-dl/phoenix-dl.jar` and install_dir`/lib-dl/jsk-dl.jar` (in that order). The Phoenix configuration must supply at least a `persistenceDirectory` entry for the component named `org.apache.river.phoenix`.

   The `PhoenixStarter` instance implements the {@link org.apache.river.start.ServiceProxyAccessor} interface, and implements the {@link org.apache.river.start.ServiceProxyAccessor#getServiceProxy getServiceProxy} method to return Phoenix's `ActivationSystem` proxy. When Phoenix's `ActivationSystem` is shutdown, the activation system implementation will invoke the `unregister` method of the {@link org.apache.river.start.LifeCycle} instance passed to the `PhoenixStarter` constructor.

   See the org.apache.river.start package documentation for details on configuring service descriptors.

## Phoenix configuration

Phoenix obtains its configuration by calling {@link net.jini.config.ConfigurationProvider#getInstance ConfigurationProvider.getInstance} with the specified configOptions.

The following entries are obtained from the configuration, all for the component named `org.apache.river.phoenix`:

• | `loginContext`
--- | ---
| Type: | `{@link javax.security.auth.login.LoginContext}`
| Default: | `null`
| Description: | JAAS login context

• | `persistenceDirectory`
--- | ---
| Type: | `String`
| Default: | no default
| Description: | log directory

• | `activatorExporter`
--- | ---
| Type: | `{@link net.jini.export.Exporter}`
| Default: | `
    new {@link net.jini.jeri.BasicJeriExporter}(
        new {@link net.jini.jeri.tcp.TcpServerEndpoint#getInstance TcpServerEndpoint.getInstance}(1198),
        new {@link net.jini.jeri.BasicILFactory}(),
        false, true,
        {@link org.apache.river.phoenix.PhoenixConstants#ACTIVATOR_UUID})
`
| Description: | activator exporter

• | `systemExporter`
--- | ---
| Type: | `{@link net.jini.export.Exporter}`
| Default: | `
    new {@link net.jini.jeri.BasicJeriExporter}(
        new {@link net.jini.jeri.tcp.TcpServerEndpoint#getInstance TcpServerEndpoint.getInstance}(1198),
        new {@link org.apache.river.phoenix.SystemAccessILFactory}(),
        false, true,
        {@link org.apache.river.phoenix.PhoenixConstants#ACTIVATION_SYSTEM_UUID})
`
| Description: | {@link java.rmi.activation.ActivationSystem} exporter

• | `monitorExporter`
--- | ---
| Type: | `{@link net.jini.export.Exporter}`
| Default: | `
    new {@link net.jini.jeri.BasicJeriExporter}(
        new {@link net.jini.jeri.tcp.TcpServerEndpoint#getInstance TcpServerEndpoint.getInstance}(1198),
        new {@link org.apache.river.phoenix.AccessILFactory}())
`
| Description: | {@link java.rmi.activation.ActivationMonitor} exporter

• | `registryExporter`
--- | ---
| Type: | `{@link net.jini.export.Exporter}`
| Default: | `new {@link org.apache.river.phoenix.RegistrySunExporter}()`
| Description: | {@link java.rmi.registry.Registry} exporter

• | `instantiatorPreparer`
--- | ---
| Type: | `{@link net.jini.security.ProxyPreparer}`
| Default: | `new {@link net.jini.security.BasicProxyPreparer}()`
| Description: | {@link java.rmi.activation.ActivationInstantiator} proxy preparer

• | `groupConfig`
--- | ---
| Type: | `String[]`
| Default: | same configuration options as Phoenix
| Description: | default activation group configuration options

• | `groupLocation`
--- | ---
| Type: | `String`
| Default: | obtain the location (a URL) from the code source of the protection domain of Phoenix's implementation class; if the URL ends in ".jar", then the default value for this entry is that URL except that ".jar" is replaced with "-group.jar", otherwise the default value is `null`
| Description: | codebase for {@link org.apache.river.phoenix.ActivationGroupImpl}

• | `groupOptions`
--- | ---
| Type: | `String[]`
| Default: | `new String[0]`
| Description: | extra options for all activation group commands

• | `groupTimeout`
--- | ---
| Type: | `int`
| Default: | `60000`
| Description: | maximum time in milliseconds to wait for group activation or termination

• | `groupThrottle`
--- | ---
| Type: | `int`
| Default: | `3`
| Description: | maximum concurrent activation group execs

• | `groupOutputHandler`
--- | ---
| Type: | `{@link org.apache.river.phoenix.GroupOutputHandler}`
| Default: | a handler that sends the group standard output to the standard output stream of Phoenix and sends the group error output to the error output stream of Phoenix
| Description: | handler for the output of activation group processes

• | `unexportTimeout`
--- | ---
| Type: | `int`
| Default: | `60000`
| Description: | maximum time in milliseconds to wait for in-progress calls to finish during shutdown before forcibly unexporting remote objects

• | `unexportWait`
--- | ---
| Type: | `int`
| Default: | `10`
| Description: | milliseconds to wait between unexport attempts during shutdown

• | `persistenceSnapshotThreshold`
--- | ---
| Type: | `int`
| Default: | `200`
| Description: | number of log updates between snapshots

If no default is listed for an entry and the configuration cannot provide that entry, Phoenix will not start.

If a non-`null` `loginContext` entry is provided, a login is performed on that context, and Phoenix executes under the resulting {@link javax.security.auth.Subject} (via {@link javax.security.auth.Subject#doAsPrivileged Subject.doAsPrivileged}).

The `persistenceDirectory` entry specifies the name of the directory Phoenix uses to write its persistent database. If the named directory does not exist, Phoenix will create it. Only the directory itself will be created; the parent directory must already exist.

Phoenix exports four remote objects: activator, activation system, activation monitor, and registry. Each object is exported using an `Exporter` obtained from the configuration. Phoenix provides various classes to facilitate the configuration of these exporters, as described further below. None of the remote objects implement any access control directly; any desired access control must be implemented through the exporters. The exported registry is always read-only, with a single binding of the name `java.rmi.activation.ActivationSystem` to the activation system proxy; this proxy also implements {@link org.apache.river.phoenix.ActivationAdmin}. For compatibility with {@link java.rmi.activation.ActivationGroup#getSystem ActivationGroup.getSystem}, the registry must be exported to the JRMP runtime, using the registry well-known object identifier. To support persistent references, the exporters for the activator and the activation system must produce proxies that are reusable across restarts of Phoenix. For JRMP and Jini extensible remote invocation (Jini ERI), this means using fixed object identifiers and fixed ports.

If the activator supports constraints (meaning the activator proxy implements {@link net.jini.core.constraint.RemoteMethodControl}), then the activation identifiers handed out by Phoenix will also implement `RemoteMethodControl`, otherwise they will not. The activator implements {@link net.jini.security.proxytrust.ServerProxyTrust} and its {@link net.jini.security.proxytrust.ServerProxyTrust#getProxyVerifier getProxyVerifier} method returns a verifier for the activation identifiers used by Phoenix. The activation identifier class implements the `getProxyTrustIterator` method required by {@link net.jini.security.proxytrust.ProxyTrustVerifier}, providing an iterator that produces the activator proxy. To support trust verification of activation identifiers, the activator proxy must implement {@link net.jini.security.proxytrust.TrustEquivalence} and must either be a bootstrap proxy that implements {@link net.jini.security.proxytrust.ProxyTrust} or be able to produce one through its own `getProxyTrustIterator` method.

Whenever an `ActivationInstantiator` proxy is received from an activation group, Phoenix passes it to the {@link net.jini.security.ProxyPreparer} given by the `instantiatorPreparer` entry, if any. The resulting proxy is used whenever Phoenix makes a remote call to that activation group.

When Phoenix starts an activation group, it relies on `phoenix-init.jar` being in the class path of the group VM, therefore this JAR file must be included directly or indirectly in the class path specified in the `CommandEnvironment` of the `ActivationGroupDesc`. Phoenix starts an activation group as follows:

- If the activation group class has a public `createGroup` method that has three parameters of type `ActivationGroupID`, `ActivationGroupDesc`, and `long`, Phoenix calls that method with the activation group identifier, the activation group descriptor, and the current group incarnation. Normally it should in turn call {@link net.jini.activation.ActivationGroup#createGroup ActivationGroup.createGroup}, to allow exporter-based remote objects to go inactive.
- If the activation group class has no such method, by default the {@link net.jini.activation.ActivationGroup#createGroup ActivationGroup.createGroup} method is called.

The class {@link org.apache.river.phoenix.ActivationGroupImpl} is used by Phoenix when an activation group descriptor does not specify a group class name. This group implementation is also configurable. The `groupConfig` entry specifies the configuration options that should be used when the group descriptor does not specify a group class and does not provide any explicit initialization data for the group. The configuration entries used by `ActivationGroupImpl` are described further below.

The `groupLocation` entry specifies the codebase, if any, that should be used to load the class {@link org.apache.river.phoenix.ActivationGroupImpl}. This codebase is used when an activation group descriptor does not specify a group class name and does not specify a group location.

The `groupOptions` entry specifies extra command line options to pass for every activation group process created by Phoenix. These options are always placed after any properties and command line options specified in the activation group descriptor, in the final command line used to create the process. The most common use of this feature is to temporarily set system properties for debugging.

The `groupTimeout` entry specifies the maximum time in milliseconds to wait after an activation group process is created before an `activeGroup` remote call must be received from that group. If the remote call is not received within that period, the attempt to activate an object within that group will terminate with an `ActivationException`. If an activation group process subsequently must be destroyed (so that a new process for the same group can be created), this entry also specifies the maximum time to wait for the process to actually terminate (after being destroyed) before giving up and proceeding to create a new process.

The `groupThrottle` entry specifies the maximum number of group processes Phoenix will create concurrently, to avoid system thrashing (particularly when Phoenix is restarting). If too many group processes need to be created at one time, creation of some will temporarily be deferred until existing creations complete.

The `groupOutputHandler` entry specifies the {@link org.apache.river.phoenix.GroupOutputHandler} for the output of activation group processes. The handler is called each time a group process is created.

The `unexportTimeout` entry specifies the maximum time in milliseconds to wait for in-progress inbound remote calls to finish during shutdown before forcibly unexporting all remote objects. The `exportWait` entry specifies the time in milliseconds to wait between unsuccessful export attempts.

Phoenix writes information about registered groups and objects to a persistent database, so that Phoenix can be restarted after a crash without losing state. As registrations are changed, incremental update records are written out, until a threshold is reached, and then a consolidated snapshot of the entire state is written out (to speed up recovery after a crash). The `persistenceSnapshotThreshold` entry specifies the the number of incremental updates to write between snapshots.

Phoenix uses the {@link java.util.logging.Logger} named `org.apache.river.phoenix` to log information at the following levels:

Level | Description
--- | ---
{@link java.util.logging.Level#SEVERE SEVERE} | persistent database snapshot failures
{@link java.util.logging.Level#WARNING WARNING} | failure to restart an activatable object that has been registered to auto-restart
{@link java.util.logging.Level#WARNING WARNING} | failure to recover from the persistent database
{@link java.util.logging.Level#INFO INFO} | startup of Phoenix
{@link java.util.logging.Level#INFO INFO} | shutdown of Phoenix
{@link java.util.logging.Level#FINE FINE} | process command line when an activation group is created

## Exporter classes

The following class is useful for exporting the registry:

- {@link org.apache.river.phoenix.RegistrySunExporter}

A custom exporter class will be needed for Java 2 Standard Edition implementations from vendors other than Sun Microsystems(TM), Inc.

The following classes are useful in conjunction with Jini ERI:

- {@link org.apache.river.phoenix.AccessILFactory}
- {@link org.apache.river.phoenix.PhoenixConstants}
- {@link org.apache.river.phoenix.SystemAccessILFactory}
- {@link org.apache.river.phoenix.SystemAccessProxyTrustILFactory}

The following classes are useful in conjunction with JRMP:

- {@link org.apache.river.phoenix.ActivatorSunJrmpExporter}
- {@link org.apache.river.phoenix.InstantiatorAccessExporter}
- {@link org.apache.river.phoenix.MonitorAccessExporter}
- {@link org.apache.river.phoenix.SystemAccessExporter}
- {@link org.apache.river.phoenix.SunJrmpExporter}

## Activation group configuration

`ActivationGroupImpl` obtains the following entries from its configuration, all for the component named `org.apache.river.phoenix`:

• | `loginContext`
--- | ---
| Type: | `{@link javax.security.auth.login.LoginContext}`
| Default: | `null`
| Description: | JAAS login context

• | `inheritGroupSubject`
--- | ---
| Type: | `boolean`
| Default: | `false`
| Description: | if `true`, group subject is inherited when an activatable object is created

• | `instantiatorExporter`
--- | ---
| Type: | `{@link net.jini.export.Exporter}`
| Default: | retains existing JRMP export of instantiator
| Description: | {@link java.rmi.activation.ActivationInstantiator} exporter

• | `monitorPreparer`
--- | ---
| Type: | `{@link net.jini.security.ProxyPreparer}`
| Default: | `new {@link net.jini.security.BasicProxyPreparer}()`
| Description: | {@link java.rmi.activation.ActivationMonitor} proxy preparer

• | `systemPreparer`
--- | ---
| Type: | `{@link net.jini.security.ProxyPreparer}`
| Default: | `new {@link net.jini.security.BasicProxyPreparer}()`
| Description: | {@link java.rmi.activation.ActivationSystem} proxy preparer

• | `unexportTimeout`
--- | ---
| Type: | `int`
| Default: | `60000`
| Description: | maximum time in milliseconds to wait for in-progress calls to finish before forcibly unexporting the group when going inactive

• | `unexportWait`
--- | ---
| Type: | `int`
| Default: | `10`
| Description: | milliseconds to wait between unexport attempts when going inactive

If a non-`null` `loginContext` entry is provided, a login is performed on that context, the group is created under the resulting {@link javax.security.auth.Subject} (set to be read-only), and all subsequent remote calls by the group to Phoenix are executed under that subject.

By default, the activation group automatically exports itself as a JRMP unicast remote object. (This is a limitation of the existing activation system design.) If an `instantiatorExporter` entry is provided, the group is unexported from the JRMP runtime and then re-exported with the provided exporter.

When the group is initially created, it passes the `ActivationSystem` proxy (obtained from the `ActivationGroupID`) to the {@link net.jini.security.ProxyPreparer} given by the `systemPreparer` entry, if any. A new `ActivationGroupID` is constructed with the resulting proxy, and is used to create the group. A remote call through the prepared `ActivationSystem` proxy is made to report the group as active, and the `ActivationMonitor` proxy returned by that call is passed to the {@link net.jini.security.ProxyPreparer} given by the `monitorPreparer` entry, if any. The prepared `ActivationMonitor` proxy will be used for all subsequent remote calls to Phoenix.

The `unexportTimeout` entry specifies the maximum time in milliseconds to wait for in-progress inbound remote calls to finish before forcibly unexporting the group when it goes inactive. The `exportWait` entry specifies the time in milliseconds to wait between unsuccessful export attempts.

The `inheritGroupSubject` entry if `true` indicates that the activation group's subject should be inherited by the access control context in which the group creates an activatable object. If the entry is `false`, then the group's subject is not inherited by that context. The default is `false`.

## Access control

Access control mechanisms for incoming remote calls should be configured into the exporters used to export the various remote objects.

For JRMP and Jini ERI, a local-host-based access control policy (equivalent to that enforced by `rmid`) can be obtained by using the exporters provided in this package.

{@link org.apache.river.phoenix.SystemPermission}, {@link org.apache.river.phoenix.ActivatorPermission}, {@link org.apache.river.phoenix.MonitorPermission}, and {@link org.apache.river.phoenix.InstantiatorPermission} can be used to express access control policies for remote objects exported with {@link net.jini.jeri.BasicJeriExporter}, by passing one of those classes to {@link net.jini.jeri.ProxyTrustILFactory} or {@link org.apache.river.phoenix.SystemAccessProxyTrustILFactory}.

{@link org.apache.river.phoenix.ExecPermission} and {@link org.apache.river.phoenix.ExecOptionPermission} can be used to express the access control policy for what activation group descriptors can be registered. These permissions are checked by {@link org.apache.river.phoenix.DefaultGroupPolicy}, which is used by {@link org.apache.river.phoenix.SystemAccessExporter}, {@link org.apache.river.phoenix.SystemAccessILFactory}, and {@link org.apache.river.phoenix.SystemAccessProxyTrustILFactory}.

## Compatibility with rmid

Activatable remote object implementations that work under `rmid` should work under Phoenix.

Activation group implementations that work under `rmid` should work under Phoenix, provided the Phoenix `ActivationSystem` is exported using a JRMP exporter. An unmodified JRMP-based group implementation will not work under Phoenix if the Phoenix `ActivationSystem` is exported using a Jini ERI exporter, because Jini ERI does not support stub replacement for JRMP implementation objects and the existing activation group design relies on such stub replacement. However, JRMP-based group implementations can be made compatible with activation systems based on Jini ERI, and still work under `rmid`, by adding a `writeReplace` method to the group implementation class that returns the stub.

Activation group implementations and activatable remote object implementations that depend on {@linkplain net.jini.activation activation extensions} supported by Phoenix will not work under `rmid`.

The persistent databases used by `rmid` and Phoenix are not compatible.

## Stopping a daemon

A running activation system daemon (not necessarily an instance of Phoenix) can be shut down gracefully with the command:

    java [options] -jar install_dir/lib/phoenix.jar -stop configOptions

In this case, the following entries are obtained from the configuration, all for the component named `org.apache.river.phoenix`:

• | `loginContext`
--- | ---
| Type: | `{@link javax.security.auth.login.LoginContext}`
| Default: | `null`
| Description: | JAAS login context

• | `systemPreparer`
--- | ---
| Type: | `{@link net.jini.security.ProxyPreparer}`
| Default: | `new {@link net.jini.security.BasicProxyPreparer}()`
| Description: | {@link java.rmi.activation.ActivationSystem} proxy preparer

• | `registryHost`
--- | ---
| Type: | `String`
| Default: | `null`
| Description: | registry host

• | `registryPort`
--- | ---
| Type: | `int`
| Default: | `1098`
| Description: | registry port

If a non-`null` `loginContext` entry is provided, a login is performed on that context, and the `shutdown` remote call is executed under the resulting {@link javax.security.auth.Subject} (via {@link javax.security.auth.Subject#doAsPrivileged Subject.doAsPrivileged}).

The activation system daemon to shut down is obtained by looking up the name `java.rmi.activation.ActivationSystem` in the registry at the host given by the `registryHost` configuration entry (defaulting to the local host) and the port given by the `registryPort` configuration entry (defaulting to port 1098).

The `ActivationSystem` proxy obtained from the registry is passed to the {@link net.jini.security.ProxyPreparer} given by the `systemPreparer` entry, if any. The resulting proxy is used for the `shutdown` remote call.

## Example configurations

The following are example Phoenix configurations, written using the syntax supported by {@link net.jini.config.ConfigurationFile}. For simplicity, each configuration example combines both entries used by Phoenix and entries used by Phoenix's default group implementation. By default, the configuration options for Phoenix will be used as the configuration options for an activation group if either the {@link org.apache.river.phoenix.ActivationGroupData} in the group's {@link java.rmi.activation.ActivationGroupDesc} does not specify configuration options or the Phoenix configuration file does not specify a `groupConfig` entry. If a configuration file is shared by both Phoenix and activation groups, some type-import-on-demand declarations (i.e., wildcard imports) may be required. If fully-qualified class names are imported, a `ConfigurationException` will be thrown if an import is encountered for a class that is not found. This may happen if a class is available to Phoenix, but is not available to the activation group, or vice versa.

    // a Jini ERI configuration specifying constraints
    import org.apache.river.config.KeyStores;
    import org.apache.river.phoenix.*;
    import net.jini.constraint.*;
    import net.jini.core.constraint.*;
    import net.jini.jeri.*;
    import net.jini.jeri.ssl.SslServerEndpoint;
    import net.jini.security.*;
    import javax.security.auth.login.LoginContext;

    org.apache.river.phoenix {
        registryExporter = new RegistrySunExporter();
        private sslPort = 2000; // pick one, cannot be 1098
        private daemonEndpoint = SslServerEndpoint.getInstance(sslPort);
        private integrity = new BasicMethodConstraints(
    	new InvocationConstraints(Integrity.YES, null));
        systemExporter =
    	new BasicJeriExporter(daemonEndpoint,
    			      new SystemAccessProxyTrustILFactory(integrity),
    			      false, true,
    			      PhoenixConstants.ACTIVATION_SYSTEM_UUID);
        activatorExporter =
    	new BasicJeriExporter(daemonEndpoint,
    			      new ProxyTrustILFactory(integrity, null),
    			      false, true,
    			      PhoenixConstants.ACTIVATOR_UUID);
        monitorExporter =
    	new BasicJeriExporter(daemonEndpoint,
    			      new ProxyTrustILFactory(
    				     integrity, MonitorPermission.class));
        private groupEndpoint = SslServerEndpoint.getInstance(0);
        instantiatorExporter =
    	new BasicJeriExporter(groupEndpoint,
    			      new ProxyTrustILFactory(
    				     integrity, InstantiatorPermission.class));
        private static keystore = KeyStores.getKeyStore(
    				    "${user.home}${/}.keystore", null);
        private mutualAuth =
    	new BasicMethodConstraints(new InvocationConstraints(
    	    new InvocationConstraint[]{
    		Integrity.YES,
    		ClientAuthentication.YES,
    		ServerAuthentication.YES,
    		new ServerMinPrincipal(
    		    KeyStores.getX500Principal("phoenix", keystore))},
    	    null));
        instantiatorPreparer = new BasicProxyPreparer(true, mutualAuth, null);
        monitorPreparer = instantiatorPreparer;
        systemPreparer = instantiatorPreparer;
        loginContext = new LoginContext("phoenix");
        persistenceDirectory = "log";
    }

    // a Jini ERI configuration

    org.apache.river.phoenix {
        persistenceDirectory = "log";
    }

    // a JRMP configuration
    import org.apache.river.phoenix.*;

    org.apache.river.phoenix {
        activatorExporter = new ActivatorSunJrmpExporter();
        systemExporter = new SystemAccessExporter();
        monitorExporter = new MonitorAccessExporter();
        instantiatorExporter = new InstantiatorAccessExporter();
        persistenceDirectory = "log";
    }

    // a JRMP configuration with no access control
    import org.apache.river.phoenix.*;
    import net.jini.jrmp.JrmpExporter;
    import java.rmi.activation.ActivationSystem;

    org.apache.river.phoenix {
        registryPort = ActivationSystem.SYSTEM_PORT;
        registryExporter = new RegistrySunExporter(registryPort);
        activatorExporter = new ActivatorSunJrmpExporter(registryPort);
        systemExporter = new SunJrmpExporter(4, registryPort);
        monitorExporter = new JrmpExporter(registryPort);
        instantiatorExporter = null;
        persistenceDirectory = "log";
    }

## Example security policies

The following are example Phoenix security policies, written using the syntax supported by the default security policy provider.

    // a secure Jini ERI Phoenix policy
    keystore "file://${user.home}/.keystore";

    grant codebase "file:install_dir/lib/jsk-platform.jar" {
      permission java.security.AllPermission;
    };

    grant codebase "file:install_dir/lib/jsk-lib.jar" {
      permission java.security.AllPermission;
    };

    grant codebase "file:install_dir/lib/phoenix.jar" {
      permission java.io.FilePermission "${user.home}${/}phoenix.config", "read";
      // next two used in configuration file
      permission java.util.PropertyPermission "user.home", "read";
      permission javax.security.auth.AuthPermission "createLoginContext.phoenix";
      permission javax.security.auth.AuthPermission "doAsPrivileged";
      // next two needed by RegistrySunExporter
      permission java.lang.RuntimePermission
            "accessClassInPackage.sun.rmi.server";
      permission java.lang.RuntimePermission
            "accessClassInPackage.sun.rmi.transport";
    };

    grant principal "phoenix" codebase "file:install_dir/lib/phoenix.jar" {
      permission javax.security.auth.AuthPermission "getSubject";
      // next two needed by RegistrySunExporter
      permission java.lang.RuntimePermission "accessDeclaredMembers";
      permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
      permission java.io.FilePermission "log", "read,write";
      permission java.io.FilePermission "log/-", "read,write,delete";
      // needed to default group location to phoenix-group.jar
      permission java.lang.RuntimePermission "getProtectionDomain";
      // next two needed for default java program for groups
      permission java.util.PropertyPermission "java.home", "read";
      permission java.io.FilePermission "${java.home}${/}bin${/}java", "execute";
      permission java.lang.RuntimePermission "shutdownHooks";
      // used in configuration file
      permission java.io.FilePermission "${user.home}${/}.keystore", "read";
      // next two needed to export remote objects
      permission java.lang.RuntimePermission "getClassLoader";
      permission net.jini.export.ExportPermission "exportRemoteInterface.org.apache.river.phoenix.Activator";
      // next two for outgoing newInstance calls to groups
      // connect to just local host (but not "localhost") would be sufficient
      permission java.net.SocketPermission "*:1024-", "connect";
      permission net.jini.security.AuthenticationPermission
            "${{self}} peer ${{self}}", "connect";
      // next two for incoming remote calls
      permission java.net.SocketPermission "*:1024-", "accept";
      permission net.jini.security.AuthenticationPermission
            "${{self}}", "accept";
    };

    // grant administrator permission to do most things
    grant principal "admin" {
      permission org.apache.river.phoenix.SystemPermission "register*";
      permission org.apache.river.phoenix.SystemPermission "get*";
      permission org.apache.river.phoenix.SystemPermission "set*";
      permission org.apache.river.phoenix.SystemPermission "shutdown";
      permission org.apache.river.phoenix.ExecOptionPermission
            "-Djava.security.auth.login.config=${user.home}${/}login";
      permission org.apache.river.phoenix.ExecOptionPermission
            "-Djavax.net.ssl.trustStore=${user.home}${/}.keystore";
      permission org.apache.river.phoenix.ExecOptionPermission
            "-Djava.security.policy=${user.home}${/}group.security.policy";
    };

    // typical service needs to verify trust, unregister, and change its descriptor
    grant principal "service" {
      permission org.apache.river.phoenix.SystemPermission "getProxyVerifier";
      permission org.apache.river.phoenix.SystemPermission "unregister*";
      permission org.apache.river.phoenix.SystemPermission "*ActivationDesc";
    };

    // for callbacks from activation groups
    grant principal "phoenix" {
      permission org.apache.river.phoenix.SystemPermission "getProxyVerifier";
      permission org.apache.river.phoenix.SystemPermission "activeGroup";
      permission org.apache.river.phoenix.MonitorPermission "*";
    };

    // part of a secure Jini ERI group policy
    keystore "file://${user.home}/.keystore";

    grant codebase "file:install_dir/lib/jsk-platform.jar" {
      permission java.security.AllPermission;
    };

    grant codebase "file:install_dir/lib/phoenix-init.jar" {
      permission java.security.AllPermission;
    };

    grant codebase "file:install_dir/lib/phoenix-group.jar" {
      permission java.lang.RuntimePermission "setContextClassLoader";
      permission java.lang.RuntimePermission "getClassLoader";
      // needed to set the ActivationGroup instance
      permission java.lang.RuntimePermission "setFactory";
      permission java.lang.RuntimePermission "modifyThreadGroup";
      permission javax.security.auth.AuthPermission "createLoginContext.phoenix";
      permission javax.security.auth.AuthPermission "getSubject";
      permission javax.security.auth.AuthPermission "doAsPrivileged";
      // next two need to call non-public constructors and activate methods
      permission java.lang.RuntimePermission "accessDeclaredMembers";
      permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
      // accept from just local host (but not "localhost") would be sufficient
      permission java.net.SocketPermission "*:1024-", "accept";
      // need to connect to local host and codebases of all activatable objects
      permission java.net.SocketPermission "*:1024-", "connect";
      permission net.jini.security.AuthenticationPermission
        "${{alias:phoenix}} peer ${{alias:phoenix}}", "connect,accept";
      permission java.io.FilePermission "${user.home}${/}phoenix.config", "read";
      // used in configuration file
      permission java.io.FilePermission "${user.home}${/}.keystore", "read";

      /* Because ActivationGroupImpl creates the activatable objects, either
       * this codebase also needs whatever permissions are needed by those
       * objects, or the objects must use AccessController.doPrivileged or
       * equivalent to avoid the need for such grants.
       */
    };

    // for remote calls from Phoenix
    grant principal "phoenix" {
      permission org.apache.river.phoenix.InstantiatorPermission "*";
    };

@since 2.0