/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.jini.jeri;

import com.sun.jini.jeri.internal.runtime.BasicExportTable;
import com.sun.jini.logging.Levels;
import java.lang.ref.WeakReference;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.ExportException;
import java.rmi.server.Unreferenced;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.jini.config.Configuration;
import net.jini.export.Exporter;
import net.jini.export.ServerContext;
import net.jini.id.Uuid;
import net.jini.id.UuidFactory;
import net.jini.io.MarshalInputStream;
import net.jini.io.context.ClientHost;
import net.jini.io.context.ClientSubject;
import net.jini.security.Security;
import net.jini.security.SecurityContext;

/**
 * An <code>Exporter</code> implementation for exporting
 * a remote object to use Jini extensible remote invocation
 * (Jini ERI).  Typically, instances of this class should be
 * obtained from a {@link Configuration} rather than being explicitly
 * constructed.
 * Each instance of <code>BasicJeriExporter</code>
 * can export only a single remote object.
 *
 * <p>The following properties (defined during construction) govern
 * invocation behavior and other characteristics of the exported remote
 * object and its proxy:
 * <ul>
 * <li>{@link ServerEndpoint}: the <code>ServerEndpoint</code> over
 * which calls are accepted.
 *
 * <li><p>{@link InvocationLayerFactory}: a factory used to obtain the remote
 * object's proxy and invocation dispatcher.
 *
 * <li><p><i>enableDGC</i> flag: if <code>true</code>, distributed
 * garbage collection (DGC) is enabled for the exported remote object,
 * and the {@link BasicObjectEndpoint} produced by this exporter
 * participates in DGC and thus constitutes a strong remote reference
 * to the remote object; if <code>false</code>, DGC is not enabled for
 * the remote object, and the <code>BasicObjectEndpoint</code> does
 * not participate in DGC and thus is a weak remote reference, so it
 * does not prevent the remote object from being garbage collected.
 *
 * <li><p><i>keepAlive</i> flag: if <code>true</code>, the virtual
 * machine is kept alive (with a non-daemon thread) while the remote
 * object remains exported via this exporter.
 *
 * <li><p>{@link Uuid Uuid}: the object identifier to use for the
 * remote object; if <code>null</code>, a unique object identifier is
 * chosen for the remote object using {@link UuidFactory#generate
 * UuidFactory.generate}.
 * </ul>
 *
 * <p>If DGC is not enabled for a remote object, then the
 * implementation always only weakly references the remote object.  If
 * DGC is enabled for a remote object, then the implementation weakly
 * references the remote object when its referenced set is empty and
 * strongly references the remote object when its referenced set is
 * not empty (see below).  If the implementation weakly references the
 * remote object and the weak reference is cleared, the remote object
 * becomes effectively unexported.
 *
 * <p>Enabling DGC is not advisable in some circumstances.  DGC should
 * not be enabled for a remote object exported with a well known
 * object identifier.  Enabling DGC with a secure remote object is
 * generally discouraged, because DGC communication is always made in
 * a client-side context in which there are no client constraints and
 * no client subject, so it can leave the remote object open to denial
 * of service attacks.  Some transport providers may not support making
 * requests without a client subject, so even if DGC is enabled in the
 * case where such a transport provider is used, DGC will be effectively
 * disabled on the client side.
 *
 * <p>Multiple remote objects can be exported on the same server endpoint,
 * and the same remote object can be exported multiple times on different
 * server endpoints with the only restriction being that a given pair of
 * object identifier and listen endpoint (derived from the server endpoint)
 * can only have one active export at any given time.
 * 
 * <p>Two instances of this class are equal only if they are references to
 * the same (<code>==</code>) object.
 * 
 * <p>The server endpoint is not transmitted in the remote reference; only the
 * derived client endpoint is transmitted.
 *
 * <p>Remote objects exported with instances of this class can call {@link
 * ServerContext#getServerContextElement
 * ServerContext.getServerContextElement}, passing the class {@link
 * ClientSubject} to obtain the authenticated identity of the client (if
 * any) for an incoming remote call, or passing the class {@link
 * ClientHost} to obtain the address of the client host.
 * 
 * <p>For remote objects exported with instances of this class, there is no
 * automatic replacement of the proxy for the remote object during
 * marshalling; either the proxy must be passed explicitly, or the remote
 * object implementation class must be serializable and have a
 * <code>writeReplace</code> method that returns its proxy.
 *
 * <h4>Distributed Garbage Collection</h4>
 *
 * The <code>BasicJeriExporter</code> class acts as the server-side
 * DGC implementation for all remote objects exported with DGC enabled
 * using its instances.
 *
 * <p>An entity known as the <i>DGC client</i> tracks the existence
 * and reachability of live remote references
 * (<code>BasicObjectEndpoint</code> instances that participate in
 * DGC) for a <code>BasicObjectEndpoint</code> class in some
 * (potentially) remote virtual machine.  A DGC client is identified
 * by a universally unique identifier (a <code>Uuid</code>).  A DGC
 * client sends <i>dirty calls</i> and <i>clean calls</i> to the
 * {@link Endpoint} of a live remote reference to inform the
 * server-side DGC implementation when the number of live remote
 * references to a given remote object it is tracking increases from
 * zero to greater than zero and decreases from greater than zero to
 * zero, respectively.  A DGC client also sends dirty calls to the
 * <code>Endpoint</code> of live remote references it is tracking to
 * renew its lease.  The client-side behavior of dirty and clean calls
 * is specified by {@link BasicObjectEndpoint}.
 *
 * <p>On the server side, for every remote object exported with DGC
 * enabled, the implementation maintains a <i>referenced set</i>,
 * which contains the <code>Uuid</code>s of the DGC clients that are
 * known to have live remote references to the remote object.  The
 * contents of the referenced set are modified as a result of dirty
 * calls, clean calls, and expiration of leases (see below).  While
 * the referenced set is not empty, the implementation strongly
 * references the remote object, so that it will not be garbage
 * collected.  While the referenced set is empty, the implementation
 * only weakly references the remote object, so that it may be garbage
 * collected (if it is not otherwise strongly reachable locally).  If
 * a remote object is garbage collected, it becomes effectively
 * unexported.  If a remote object that is an instance of {@link
 * Unreferenced} is exported with DGC enabled, then whenever the size
 * of its referenced set transitions from greater than zero to zero,
 * its {@link Unreferenced#unreferenced unreferenced} method will be
 * invoked (before the strong reference is dropped).  Note that a
 * referenced set spans multiple exports of the same (identical)
 * remote object with <code>BasicJeriExporter</code>.
 *
 * <p>For every <code>RequestDispatcher</code> passed by
 * <code>BasicJeriExporter</code> to a <code>ListenEndpoint</code> as
 * part of exporting, whenever it has at least one remote object
 * exported with DGC enabled, it also has an implicitly exported
 * remote object that represents the server-side DGC implementation.
 * This remote object is effectively exported with an object
 * identifier of <code>d32cd1bc-273c-11b2-8841-080020c9e4a1</code> and
 * an <code>InvocationDispatcher</code> that behaves like a {@link
 * BasicInvocationDispatcher} with no server constraints, with a
 * {@link BasicInvocationDispatcher#createMarshalInputStream
 * createMarshalInputStream} implementation that returns a {@link
 * MarshalInputStream} that ignores codebase annotations, and with
 * support for at least the following remote methods:
 *
 * <pre>
 *     long dirty(Uuid clientID, long sequenceNum, Uuid[] ids)
 *         throws {@link RemoteException};
 *
 *     void clean(Uuid clientID, long sequenceNum, Uuid[] ids, boolean strong)
 *         throws RemoteException;
 * </pre>
 *
 * <code>clientID</code> identifies the DGC client that is making the
 * dirty or clean call, and <code>sequenceNum</code> identifies the
 * sequence number of the dirty or clean call with respect to other
 * dirty and clean calls from the same DGC client.  The sequence
 * numbers identify the correct order of semantic interpretation of
 * dirty and clean calls from the same DGC client, regardless of the
 * order in which they arrive.  The well-known object identifier for
 * the server-side DGC implementation is reserved; attempting to
 * export any other remote object with that object identifier always
 * throws an {@link ExportException}.
 *
 * <p>A dirty call is processed as follows:
 *
 * <ul>
 *
 * <li>It establishes or renews the DGC lease for the identified DGC
 * client.  The duration of the granted lease, which is chosen by the
 * implementation, is conveyed as the value returned by the dirty
 * call, in milliseconds starting from the some time during the
 * processing of the dirty call.  While the lease for a DGC client is
 * valid (not expired), the DGC client is preserved in referenced sets
 * of exported remote objects.
 *
 * <li><p>It adds the DGC client's <code>Uuid</code> to the referenced
 * sets of the exported remote objects identified by <code>ids</code>,
 * if any, so that they are prevented from being garbage collected.
 * For each <code>Uuid</code> in <code>ids</code>:
 *
 * <blockquote>
 *
 * The identified remote object is the remote object exported with
 * that <code>Uuid</code> on the <code>ListenEndpoint</code> (and thus
 * <code>RequestDispatcher</code>) that the dirty call was received
 * on.  If no such exported remote object exists (for example, if it
 * has been garbage collected), then that <code>Uuid</code> in
 * <code>ids</code> is ignored.  If the sequence number is less than
 * the last recorded sequence number of a dirty or clean call for the
 * identified remote object from the same DGC client, then the remote
 * object's referenced set is not modified.  Otherwise, the DGC
 * client's <code>Uuid</code> is added to the remote object's
 * referenced set (if not already present).  If this addition causes
 * the referenced set to transition from empty to non-empty, then the
 * implementation starts strongly referencing the remote object.
 *
 * </blockquote>
 *
 * </ul>
 *
 * <p>A clean call is processed as follows:
 *
 * <ul>
 *
 * <li>It removes the DGC client's <code>Uuid</code> from the
 * referenced sets of the exported remote objects identified by
 * <code>ids</code>, so that they are not prevented from being garbage
 * collected by the given DGC client.  For each <code>Uuid</code> in
 * <code>ids</code>:
 *
 * <blockquote>
 *
 * <p>The identified remote object is the remote object exported with
 * that <code>Uuid</code> on the <code>ListenEndpoint</code> (and thus
 * <code>RequestDispatcher</code>) that the dirty call was received
 * on.  If no such exported remote object exists (for example, if it
 * has been garbage collected), then that <code>Uuid</code> in
 * <code>ids</code> is ignored.  If the sequence number is less then
 * the last recorded sequence number of a dirty or clean call for the
 * identified remote object from the same DGC client, then the remote
 * object's referenced set is not modified.  Otherwise, the DGC
 * client's <code>Uuid</code> is removed from the remote object's
 * referenced set (if it is present).  If this removal causes the
 * referenced set to transition from non-empty to empty, then the
 * implementation starts only weakly referencing the remote object
 * (and before doing so, if the remote object is an instance of
 * <code>Unreferenced</code>, its <code>unreferenced</code> method is
 * invoked).  If <code>strong</code> is <code>true</code>, then a
 * record is kept of the specified sequence number from the DGC client
 * for some reasonable period of time, in the event of a dirty call
 * that might arrive later with a lower sequence number.
 *
 * </blockquote>
 *
 * </ul>
 *
 * <p>If the implementation detects that the most recently granted DGC
 * lease for a given DGC client has expired, then it assumes that the
 * DGC client has abnormally terminated, and the DGC client's
 * <code>Uuid</code> is removed from the referenced sets of all
 * exported remote objects.  If this removal causes a referenced set
 * to transition from non-empty to empty, then the implementation
 * starts only weakly referencing the corresponding remote object (and
 * before doing so, if the remote object is an instance of
 * <code>Unreferenced</code>, its <code>unreferenced</code> method is
 * invoked).
 *
 * <p>Unexporting a remote object with a
 * <code>BasicJeriExporter</code> causes the removal of DGC client
 * <code>Uuid</code>s from the remote object's referenced set that
 * were only present because of dirty calls that were received as a
 * result of exporting it with that <code>BasicJeriExporter</code>.
 * If the remote object remains exported with DGC enabled by another
 * <code>BasicJeriExporter</code> and this removal causes the
 * referenced set to transition from non-empty to empty, then the
 * implementation starts only weakly referencing the remote object
 * (and before doing so, if the remote object is an instance of
 * <code>Unreferenced</code>, its <code>unreferenced</code> method is
 * invoked).
 *
 * <p>When the implementation invokes a remote object's
 * <code>unreferenced</code> method, it does so with the security
 * context and context class loader in effect when the remote object
 * was exported.  If the remote object is currently exported more than
 * once, then the security context and context class loader in effect
 * for any one of those exports are used.
 *
 * @author	Sun Microsystems, Inc.
 * @since 2.0
 *
 * @com.sun.jini.impl
 *
 * <p>This implementation uses the {@link Logger} named
 * <code>net.jini.jeri.BasicJeriExporter</code> to log
 * information at the following levels:
 *
 * <table summary="Describes what is logged by BasicJeriExporter at various
 *        logging levels" border=1 cellpadding=5>
 *
 * <tr> <th> Level <th> Description
 *
 * <tr> <td> {@link Levels#FAILED FAILED} <td> incoming request for
 * unrecognized object identifier (no such object)
 *
 * <tr> <td> {@link Levels#FAILED FAILED} <td> I/O exception
 * dispatching incoming request
 *
 * <tr> <td> {@link Level#FINE FINE} <td> successful export of object
 * 
 * <tr> <td> {@link Level#FINE FINE} <td> attempted unexport of object
 *
 * <tr> <td> {@link Level#FINE FINE} <td> garbage collection of
 * exported object
 *
 * <tr> <td> {@link Level#FINE FINEST} <td> detailed implementation
 * activity
 *
 * </table>
 **/
public final class BasicJeriExporter implements Exporter {
    
    private static final Logger logger =
	Logger.getLogger("net.jini.jeri.BasicJeriExporter");

    private final ServerEndpoint se;
    private final InvocationLayerFactory ilf;
    private final boolean enableDGC;
    private final boolean keepAlive;
    private final Uuid id;

    private boolean used = false;
    private BasicExportTable.Entry entry;
    private WeakReference weakImplContainer = null;

    private static final BasicExportTable table = new BasicExportTable();

    /**
     * Creates a new <code>BasicJeriExporter</code> with the given server
     * endpoint and invocation layer factory.  The other properties of the
     * exporter default as follows: the <code>enableDGC</code> flag is
     * <code>false</code>, the <code>keepAlive</code> flag is
     * <code>true</code>, and the object identifier is chosen by invoking
     * {@link UuidFactory#generate UuidFactory.generate}.
     *
     * @param	se the server endpoint over which calls may be accepted
     * @param	ilf the factory for creating the remote object's
     *		proxy and invocation dispatcher
     * @throws	NullPointerException if <code>se</code> or <code>ilf</code>
     *		is <code>null</code>
     **/
    public BasicJeriExporter(ServerEndpoint se, InvocationLayerFactory ilf) {
	this(se, ilf, false, true);
    }
    
    /**
     * Creates a new <code>BasicJeriExporter</code> with the given server
     * endpoint, invocation layer factory, <code>enableDGC</code> flag, and
     * <code>keepAlive</code> flag.  The object identifier is chosen by
     * invoking {@link UuidFactory#generate UuidFactory.generate}.
     *
     * @param	se the server endpoint over which calls may be accepted
     * @param	ilf the factory for creating the remote object's
     *		proxy and invocation dispatcher
     * @param	enableDGC if <code>true</code>, DGC is enabled to the object
     *		on this server endpoint
     * @param	keepAlive if <code>true</code>, the VM is kept alive
     *		while the object (exported via this exporter) remains
     *		exported
     * @throws	NullPointerException if <code>se</code> or <code>ilf</code>
     *		is <code>null</code>
     **/
    public BasicJeriExporter(ServerEndpoint se,
			     InvocationLayerFactory ilf,
			     boolean enableDGC,
			     boolean keepAlive)
    {
	this(se, ilf, enableDGC, keepAlive, null);
    }

    /**
     * Creates a new <code>BasicJeriExporter</code> with the given server
     * endpoint, invocation layer factory, <code>enableDGC</code> flag,
     * <code>keepAlive</code> flag, and object identifier.  If
     * <code>id</code> is <code>null</code>, the object identifier is
     * chosen by invoking {@link UuidFactory#generate
     * UuidFactory.generate}.
     *
     * @param	se the server endpoint over which calls may be accepted
     * @param	ilf the factory for creating the remote object's proxy
     *		and invocation dispatcher
     * @param	enableDGC if <code>true</code>, DGC is enabled to the object
     *		on this server endpoint
     * @param	keepAlive if <code>true</code>, the VM is kept alive
     *		while the object (exported via this exporter) remains
     *		exported
     * @param	id an object identifier or <code>null</code>
     * @throws	NullPointerException if <code>se</code> or <code>ilf</code>
     *		is <code>null</code>
     **/
    public BasicJeriExporter(ServerEndpoint se,
			     InvocationLayerFactory ilf,
			     boolean enableDGC,
			     boolean keepAlive,
			     Uuid id)
    {
	if (se == null || ilf == null) {
	    throw new NullPointerException();
	}
	this.se = se;
	this.ilf = ilf;
	this.id = ((id == null) ? UuidFactory.generate() : id);
	this.enableDGC = enableDGC;
	this.keepAlive = keepAlive;
    }

    /**
     * Returns the server endpoint for this exporter.
     *
     * @return the server endpoint
     **/
    public ServerEndpoint getServerEndpoint() {
	return se;
    }

    /**
     * Returns the <code>InvocationLayerFactory</code> for this
     * exporter.
     *
     * @return the factory
     **/
    public InvocationLayerFactory getInvocationLayerFactory() {
	return ilf;
    }

    /**
     * Returns <code>true</code> if DGC is enabled on the server endpoint to
     * the object corresponding to this exporter; otherwise
     * returns <code>false</code>.
     *
     * @return  <code>true</code> if DGC is enabled;
     *		<code>false</code> otherwise
     **/
    public boolean getEnableDGC() {
	return enableDGC;
    }

    /**
     * Returns <code>true</code> if the virtual machine is kept alive while
     * the object corresponding to this exporter is exported; otherwise
     * returns <code>false</code>.
     *
     * @return  <code>true</code> if VM is kept alive while object is
     *          exported; <code>false</code> otherwise
     **/
    public boolean getKeepAlive() {
	return keepAlive;
    }
    
    /**
     * Returns the object identifier for this exporter.
     *
     * @return the object identifier
     **/
    public Uuid getObjectIdentifier() {
	return id;
    }
    
    /**
     * Exports the specified remote object and returns a proxy for the
     * remote object.  This method cannot be called more than once to
     * export a remote object or an <code>IllegalStateException</code> will
     * be thrown.
     *
     * <p>A {@link BasicObjectEndpoint} instance is created with the object
     * identifier of this exporter, the {@link Endpoint} obtained from
     * listening on the server endpoint (see below), and the
     * <code>enableDGC</code> flag of this exporter.
     *
     * <p>The client <code>Endpoint</code> for the
     * <code>BasicObjectEndpoint</code> is obtained by invoking {@link
     * ServerEndpoint#enumerateListenEndpoints enumerateListenEndpoints} on
     * the server endpoint with a {@link ServerEndpoint.ListenContext}
     * whose {@link ServerEndpoint.ListenContext#addListenEndpoint
     * addListenEndpoint} method is implemented as follows: <ul>
     *
     * <li>Invokes {@link ServerEndpoint.ListenEndpoint#checkPermissions
     * checkPermissions} on the supplied listen endpoint.
     *
     * <li>If the supplied listen endpoint has the same class and is equal
     * to another listen endpoint that has already been listened on,
     * returns the {@link ServerEndpoint.ListenCookie} corresponding to the
     * previous <code>listen</code> operation.  Otherwise, it creates a
     * {@link RequestDispatcher} to handle inbound requests dispatched by
     * the listen endpoint, invokes {@link
     * ServerEndpoint.ListenEndpoint#listen listen} on the listen endpoint
     * (passing the request dispatcher) within an action passed to the
     * {@link Security#doPrivileged Security.doPrivileged} method, and
     * returns the <code>ServerEndpoint.ListenCookie</code> obtained by
     * invoking {@link ServerEndpoint.ListenHandle#getCookie getCookie} on
     * the {@link ServerEndpoint.ListenHandle} returned from the
     * <code>listen</code> invocation.
     * </ul>
     *
     * <p>A <code>RequestDispatcher</code> for a listen endpoint handles a
     * dispatched inbound request (when its {@link
     * RequestDispatcher#dispatch dispatch} method is invoked) as follows.
     * The request dispatcher reads the object identifer of the target
     * object being invoked by invoking {@link UuidFactory#read
     * UuidFactory.read} on the request input stream of the inbound
     * request.  If no exported object corresponds to the object identifier
     * read, it closes the request input stream, writes <code>0x00</code>
     * to the response output stream, and closes the response output
     * stream.  Otherwise, it writes <code>0x01</code> to the response
     * output stream, and invokes the {@link InvocationDispatcher#dispatch
     * dispatch} method on the invocation dispatcher passing the target
     * object, the inbound request, and the server context collection (see
     * below).
     *
     * <p>A proxy and an invocation dispatcher are created by
     * calling the {@link InvocationLayerFactory#createInstances
     * createInstances} method of this exporter's invocation layer factory,
     * passing the remote object, the <code>BasicObjectEndpoint</code>, and
     * the server endpoint (as the {@link ServerCapabilities}). The proxy
     * is returned by this method. The invocation dispatcher is called for
     * each incoming remote call to this exporter's object identifier
     * received from this exporter's server endpoint, passing the remote
     * object and the {@link InboundRequest} received from the transport
     * layer.
     *
     * <p>Each call to the invocation dispatcher's {@link
     * InvocationDispatcher#dispatch dispatch} method is invoked with
     * the following thread context:
     * <ul>
     * <li><code>dispatch</code> is invoked in a {@link
     *     PrivilegedAction} wrapped by a {@link SecurityContext}
     *     obtained when this method was invoked, with the {@link
     *     AccessControlContext} of that <code>SecurityContext</code>
     *     in effect.
     * <li>The context class loader is the context class loader
     *     in effect when this method was invoked.
     * <li>Each call to the dispatcher is made using {@link
     *     ServerContext#doWithServerContext
     *     ServerContext.doWithServerContext} with a server context
     *     collection that is an unmodifiable view of the context
     *     collection populated by invoking the {@link
     *     InboundRequest#populateContext populateContext} method on the
     *     inbound request passing a modifiable collection.  The invocation
     *     dispatcher's {@link InvocationDispatcher#dispatch dispatch}
     *     method is invoked with the <code>impl</code>, the inbound
     *     request, and that modifiable server context collection.
     * </ul>
     *
     * <p>There is no replacement of the proxy for the implementation
     * object during marshalling; either the proxy must be passed
     * explicitly in a remote call, or the implementation class must be
     * serializable and have a <code>writeReplace</code> method that
     * returns the proxy.
     *
     * @throws	ExportException if an object is already exported
     *		with the same object identifier and server endpoint, or
     *		the invocation layer factory cannot create a proxy or
     *		invocation dispatcher, or some other problem occurs while
     *		exporting the object 
     * @throws	NullPointerException {@inheritDoc}
     * @throws	IllegalStateException {@inheritDoc}
     * @throws	SecurityException if invoking the
     *		<code>checkPermissions</code> method on any of the listen
     *		endpoints throws a <code>SecurityException</code>
     **/
    public synchronized Remote export(Remote impl)
	throws ExportException
    {
	/*
	 * Check if object is already exported; disallow exporting more
	 * than once via this exporter.
	 */
	if (used) {
	    throw new IllegalStateException(
		"object already exported via this exporter");
	}
	assert (entry == null);		// ()s to work around javadoc bug

	/*
	 * Export the remote object.
	 */
	entry = table.export(impl, se, enableDGC, keepAlive, id);
	used = true;
	
	/*
	 * Create proxy and invocation dispatcher for the remote object.
	 *
	 * (Use package-private BasicObjectEndpoint constructor to suppress
	 * DGC activity for this local live reference and to keep the impl
	 * strongly referenced through it.)
	 */
	Remote proxy;
	InvocationLayerFactory.Instances inst = null;
	try {
	    ImplContainer implContainer = new ImplContainer(impl);
	    weakImplContainer = new WeakReference(implContainer);
	    ObjectEndpoint oe =
		new BasicObjectEndpoint(entry.getEndpoint(), id,
					enableDGC, implContainer);
	    inst = ilf.createInstances(impl, oe, se);
	    entry.setInvocationDispatcher(inst.getInvocationDispatcher());
	    proxy = inst.getProxy();

	    if (logger.isLoggable(Level.FINE)) {
		logger.log(Level.FINE,
			   "export of {0} via {1} returns proxy {2}",
			   new Object[]{ impl, this, proxy });
	    }
	} finally {
	    if (inst == null) {
		unexport(true);
	    }
	} 
	
	return proxy;
    }

    /**
     * Unexports the remote object exported via the exporter's
     * {@link #export export} method such that incoming remote calls
     * to the object identifier in this exporter are no longer accepted
     * through the server endpoint in this exporter.
     *
     * <p>If <code>force</code> is <code>true</code>, the object
     * is forcibly unexported even if there are pending or in-progress remote
     * calls to the object identifier through the server endpoint.  If
     * <code>force</code> is <code>false</code>, the object is only
     * unexported if there are no pending or in-progress remote calls to the
     * object identifier through the server endpoint.
     *
     * <p>The return value is <code>true</code> if the object is (or was
     * previously) unexported, and <code>false</code> if the object is still
     * exported.
     *
     * @throws	IllegalStateException {@inheritDoc}
     **/
    public synchronized boolean unexport(boolean force) {
	
	if (!used) {
	    throw new IllegalStateException(
		"no object exported via this exporter");
	}

	if (entry != null && entry.unexport(force)) {
	    entry = null;
	    ImplContainer implContainer =
		(ImplContainer) weakImplContainer.get();
	    if (implContainer != null) {
		implContainer.clearImpl();
	    }
	}

	boolean result = entry == null;
	if (logger.isLoggable(Level.FINE)) {
	    logger.log(Level.FINE, "unexport on {0} returns {1}",
		new Object[]{ this, Boolean.valueOf(result) });
	}
	return result;
    }
    
    /**
     * Returns the string representation for this exporter.
     * 
     * @return the string representation for this exporter
     **/
    public String toString() {
	return "BasicJeriExporter[" + se + "," + id + "]";
    }

    /**
     * Container for an impl object.
     *
     * BasicJeriExporter, when exporting an impl, passes an impl container
     * to the package-private BasicObjectEndpoint constructor so that the
     * BasicObjectEndpoint can reference the impl strongly (through the
     * container) while the object is exported.  The BasicJeriExporter
     * instance holds onto the impl container weakly so it won't prevent
     * the impl from being garbage collected; only the local stub that
     * references the BasicObjectEndpoint will prevent the impl from being
     * garbage collected.
     *
     * If the object is explicitly unexported via BasicJeriExporter, the
     * BasicJeriExporter instance clears the impl field (if the container
     * hasn't been garbage collected) so a reachable stub that references
     * the container (via the BasicObjectEndpoint in the stub) will not
     * prevent the impl from being garbage collected.
     **/
    private static class ImplContainer {

	private Object impl;

	ImplContainer(Object impl) {
	    this.impl = impl;
	}

	void clearImpl() {
	    impl = null;
	}
    }
}
