harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ghar...@apache.org
Subject svn commit: r407625 [11/16] - in /incubator/harmony/enhanced/classlib/trunk/modules/rmi3: ./ doc/ make/ src/ src/common/ src/common/javasrc/ src/common/javasrc/java/ src/common/javasrc/java/rmi/ src/common/javasrc/java/rmi/activation/ src/common/javasr...
Date Thu, 18 May 2006 20:01:30 GMT
Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef.java Thu May 18 13:01:22 2006
@@ -0,0 +1,638 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed 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.
+ */
+
+/**
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.2 $
+ */
+package org.apache.harmony.rmi.remoteref;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.BindException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.ServerError;
+import java.rmi.ServerException;
+import java.rmi.StubNotFoundException;
+import java.rmi.UnmarshalException;
+import java.rmi.server.ExportException;
+import java.rmi.server.ObjID;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RemoteCall;
+import java.rmi.server.RemoteObjectInvocationHandler;
+import java.rmi.server.RemoteRef;
+import java.rmi.server.RemoteStub;
+import java.rmi.server.ServerNotActiveException;
+import java.rmi.server.ServerRef;
+import java.rmi.server.Skeleton;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.harmony.rmi.common.GetBooleanPropAction;
+import org.apache.harmony.rmi.common.RMILog;
+import org.apache.harmony.rmi.common.RMIProperties;
+import org.apache.harmony.rmi.common.RMIUtil;
+import org.apache.harmony.rmi.server.RMIReference;
+import org.apache.harmony.rmi.server.ServerConnectionManager;
+import org.apache.harmony.rmi.transport.Endpoint;
+import org.apache.harmony.rmi.transport.RMIObjectInputStream;
+import org.apache.harmony.rmi.transport.RMIObjectOutputStream;
+
+
+/**
+ * Implementation of server-side handle for remote objects.
+ *
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.2 $
+ */
+public class UnicastServerRef extends UnicastRef implements ServerRef {
+
+    private static final long serialVersionUID = 3913676048828136951L;
+
+    /** Implementation which this handle refers to. */
+    protected RMIReference ref = null;
+
+    /**
+     * Skeleton for this remote object if we use RMI protocol 1.1 or null
+     * if we use RMI protocol 1.2.
+     */
+    protected Skeleton skel = null;
+
+    /**
+     * Map with remote methods.
+     * Methods hash codes are the keys in the table.
+     */
+    protected Map remoteMethods = new HashMap();
+
+    /** True if the handled remote object is system. */
+    protected boolean isSystem;
+
+    /**
+     * ServerConnectionManager accepting connections for this ServerRef.
+     */
+    protected ServerConnectionManager mgr;
+
+    // The name of Remote class for loggin purposes.
+    private String implClassName = null;
+
+    // Log where to write server-side log of remote calls.
+    private static final RMILog serverCallsLog = RMILog.getServerCallsLog();
+
+    // Log where to write server-side log of remote reference activity
+    private static final RMILog serverRefLog = RMILog.getServerRefLog();
+
+    // Should we suppress stack traces before sending to client or not
+    private static final boolean suppressST =
+        ((Boolean) AccessController.doPrivileged(
+            new GetBooleanPropAction(RMIProperties.SUPPRESSSTACKTRACES_PROP)))
+                .booleanValue();
+
+    // Should we print on server side stack traces or not
+    private static final boolean printST =
+        ((Boolean) AccessController.doPrivileged(
+                new GetBooleanPropAction(RMIProperties.EXCEPTIONTRACE_PROP)))
+                    .booleanValue();
+
+    // Should we generate dynamic proxy stubs only or not.
+    private static final boolean ignoreStubClasses =
+        ((Boolean) AccessController.doPrivileged(
+                new GetBooleanPropAction(RMIProperties.IGNORESTUBCLASSES_PROP)))
+                    .booleanValue();
+
+    /**
+     * Constructs default UnicastServerRef listening on anonymous port.
+     */
+    public UnicastServerRef() {
+        this(0);
+    }
+
+    /**
+     * Constructs UnicastServerRef listening on the port specified.
+     *
+     * @param port port where this UnicastServerRef will listen for connections
+     */
+    public UnicastServerRef(int port) {
+        this(port, null, null, new ObjID());
+    }
+
+    /**
+     * Constructs UnicastServerRef listening on the port specified and
+     * having the given client and server socket factories.
+     *
+     * @param port port where this UnicastServerRef will listen for connections
+     * @param csf client-side socket factory for creating client sockets
+     * @param ssf server-side socket factory for creating server sockets
+     */
+    public UnicastServerRef(int port,
+                            RMIClientSocketFactory csf,
+                            RMIServerSocketFactory ssf) {
+        this(port, csf, ssf, new ObjID());
+    }
+
+    /**
+     * Constructs UnicastServerRef listening on the port specified,
+     * using specified client and server socket factories and
+     * having the given ObjID.
+     *
+     * @param port port where this UnicastServerRef will listen for connections
+     * @param csf client-side socket factory for creating client sockets
+     * @param ssf server-side socket factory for creating server sockets
+     * @param objId Object ID of remote object
+     */
+    public UnicastServerRef(int port,
+                            RMIClientSocketFactory csf,
+                            RMIServerSocketFactory ssf,
+                            ObjID objId) {
+        super();
+        isLocal = true;
+        ep = new Endpoint(port, csf, ssf);
+        this.objId = objId;
+    }
+
+    /**
+     * Constructs UnicastServerRef using specified Endpoint and ObjID.
+     *
+     * @param ep Endpoint for remote calls
+     * @param objId Object ID of remote object
+     */
+    public UnicastServerRef(Endpoint ep, ObjID objId) {
+        super(ep, objId);
+    }
+
+    /**
+     * @see ServerRef.exportObject(Remote, Object)
+     */
+    public RemoteStub exportObject(Remote obj, Object data)
+            throws RemoteException {
+        return (RemoteStub) exportObject(obj, data, false, true, false);
+    }
+
+    /**
+     * @see ServerRef.getClientHost()
+     */
+    public String getClientHost() throws ServerNotActiveException {
+        String host = ServerConnectionManager.getClientHost();
+
+        if (host == null) {
+            throw new ServerNotActiveException(
+                    "There are no in-progress RMI calls in the current thead.");
+        }
+        return host;
+    }
+
+    /**
+     * @see RemoteRef.getRefClass(ObjectOutput)
+     */
+    public String getRefClass(ObjectOutput out) {
+        return "UnicastServerRef";
+    }
+
+    /**
+     * For this type of ref no additional data is written to the stream.
+     */
+    public void writeExternal(ObjectOutput out) throws IOException {
+    }
+
+    /**
+     * For this type of ref no additional data is read from the stream.
+     */
+    public void readExternal(ObjectInput in)
+            throws IOException, ClassNotFoundException {
+    }
+
+    /**
+     * Exports remote object so it becomes available for remote calls.
+     *
+     * @param obj remote object implementation
+     * @param data additional data needed for exporting the object (not used)
+     * @param useProxyStubs If true then Proxy stubs will be generated if stub
+     *        class could not be found in classpath and codebase; if false Proxy
+     *        stubs will not be tried (this is needed for
+     *        UnicastRemoteObject.exportObject(Remote) method because it
+     *        returns RemoteStub class (but Proxy class could not be casted
+     *        to it)
+     * @param startListen if false, ServerSocket listening thread will not be
+     *        started (this is used for DGC, for example); otherwise listening
+     *        thread will be started and object becomes available for
+     *        connections from clients
+     * @param isSystem if true then existence of this object will not prevent
+     *        VM from exiting (for example, for rmiregistry)
+     *
+     * @throws RemoteException if any exception occured while trying to export
+     *         the object
+     */
+    public Remote exportObject(Remote obj,
+                               Object data,
+                               boolean useProxyStubs,
+                               boolean startListen,
+                               boolean isSystem)
+            throws RemoteException {
+        this.isSystem = isSystem;
+        ref = new RMIReference(obj);
+        implClassName = obj.getClass().getName();
+        Remote stub = null;
+
+        // obtain class directly implementing Remote interface
+        Class remoteClass = RMIUtil.getRemoteClass(obj.getClass());
+
+        // load and instantiate skel class if any
+        skel = getSkelInstance(remoteClass);
+        boolean isProxyStub = false;
+
+        if (serverRefLog.isLoggable(RMILog.VERBOSE)) {
+            serverRefLog.log(RMILog.VERBOSE, "Obtaining stub class for: "
+                    + remoteClass.getName());
+        }
+        Class stubClass = null;
+
+        if (!useProxyStubs || !ignoreStubClasses) {
+            // load stub class statically generated by rmic
+            stubClass = loadStubClass(remoteClass, !useProxyStubs);
+
+            if (serverRefLog.isLoggable(RMILog.VERBOSE)) {
+                serverRefLog.log(RMILog.VERBOSE, "Loaded \"static\" stub for "
+                        + remoteClass.getName());
+            }
+        }
+
+        if (stubClass == null) {
+            // try to create dynamic proxy stub class
+            try {
+                stubClass = Proxy.getProxyClass(obj.getClass().getClassLoader(),
+                        RMIUtil.getRemoteInterfaces(obj.getClass()));
+                //stubClass = RMIClassLoader.loadProxyClass(null,
+                //        RMIUtil.getRemoteInterfacesNames(obj.getClass()),
+                //        obj.getClass().getClassLoader());
+
+                if (serverRefLog.isLoggable(RMILog.VERBOSE)) {
+                    serverRefLog.log(RMILog.VERBOSE, "Loaded dynamic stub for "
+                            + remoteClass.getName());
+                }
+                isProxyStub = true;
+            } catch (Exception ex) {
+                throw new StubNotFoundException(
+                        "Unable to create dynamic proxy stub class", ex);
+            }
+        }
+
+        try {
+
+            // add remote method which could be invoked to the hash table
+            remoteMethods = RMIUtil.getRemoteMethods(obj.getClass());
+
+            /*
+             * Make all remote methods accessible (for protected or
+             * package-protected cases).
+             */
+            AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    AccessibleObject.setAccessible(
+                            (Method []) (remoteMethods.values().toArray(
+                                    new Method[remoteMethods.size()])), true);
+                    return null;
+                }
+            });
+
+            // init stub
+            UnicastRef rref = getClientRef(ep, objId);
+
+            if (!isProxyStub) {
+                stub = (RemoteStub) stubClass.getConstructor(
+                        new Class[] { RemoteRef.class }).newInstance(
+                                new Object[] { rref });
+            } else {
+                stub = (Remote) stubClass.getConstructor(
+                        new Class[] { InvocationHandler.class }).newInstance(
+                            new Object[] {
+                                new RemoteObjectInvocationHandler( rref ) });
+            }
+
+            if (serverRefLog.isLoggable(RMILog.VERBOSE)) {
+                serverRefLog.log(RMILog.VERBOSE, "Instantiated stub: " + stub);
+            }
+
+            if (startListen) {
+                // start listening thread
+                mgr = ServerConnectionManager.getMgr(ep);
+            }
+        } catch (BindException be) {
+            throw new ExportException("Unable to export object: port "
+                    + ep.getPort() + " already in use", be);
+        } catch (Exception ex) {
+            throw new ExportException("Unable to export object on port "
+                    + ep.getPort(), ex);
+        }
+        return stub;
+    }
+
+    /**
+     * Returns true if force parameter is false and there are no in-progress
+     * calls to the object handled by this ref and false otherwise. This method
+     * could be overriden by subclasses to "really" unexport handled object.
+     *
+     * @param force if true then we may not care about active calls
+     *
+     * @return true if force parameter is false and there are no in-progress
+     *         calls to the object handled by this ref and false otherwise
+     */
+    public boolean unexportObject(boolean force) {
+        return force ? true : !mgr.hasActiveCalls();
+    }
+
+    /**
+     * Returns true if the handled Remote object is system and false otherwise.
+     *
+     * @return true if the handled Remote object is system and false otherwise
+     */
+    public boolean isSystem() {
+        return isSystem;
+    }
+
+    /**
+     * Performs actual remote method invocation.
+     *
+     * @param call RemoteCall
+     *
+     * @throws IOException if any I/O error occured during remote method call
+     */
+    public void processCall(RemoteCall call) throws IOException {
+        // read method and parameters
+        RMIObjectInputStream oin = (RMIObjectInputStream) call.getInputStream();
+        int op = oin.readInt(); // read operation
+        long h = oin.readLong(); // read method hash
+
+        if (op != -1) {
+            // Using 1.1. RMI protocol version
+            if (skel == null) {
+                throw new UnmarshalException("Skeleton class not found.");
+            }
+            String m = skel.getOperations()[op].toString();
+            logServerCall(m);
+
+            try {
+                skel.dispatch((Remote) ref.get(), call, op, h);
+            } catch (Throwable t) {
+                Exception ex = prepareException(m, t);
+                RMIObjectOutputStream oout =
+                        (RMIObjectOutputStream) call.getResultStream(false);
+                oout.writeObject(ex);
+            }
+
+            try {
+                call.getOutputStream().flush();
+            } catch (IOException ioe) {
+            }
+            return;
+        }
+
+        // Using 1.2 RMI protocol version
+        Method m = (Method) remoteMethods.get(new Long(h));
+
+        if (m == null) {
+            throw new UnmarshalException("Method with hash = "  + h
+                    + " not found.");
+        }
+        logServerCall(m.toString());
+        Object[] params = readParams(m, oin);
+        call.releaseInputStream();
+        Object toReturn = null;
+        Throwable toThrow = null;
+
+        // locally call the method
+        try {
+            toReturn = m.invoke(ref.get(), params);
+        } catch (InvocationTargetException ite) {
+            toThrow = prepareException(m.toString(),
+                    ((InvocationTargetException) ite).getTargetException());
+        } catch (Throwable t) {
+            toThrow = prepareException(m.toString(), t);
+        }
+
+        // return result of method call
+        RMIObjectOutputStream oout =
+                (RMIObjectOutputStream) call.getResultStream(toThrow == null);
+
+        try {
+            if (toThrow != null) {
+                oout.writeObject(toThrow);
+            } else if (toReturn != null) {
+                oout.writeRMIObject(toReturn, m.getReturnType());
+            } else if (m.getReturnType() != Void.TYPE) {
+                oout.writeObject(null);
+            }
+            oout.flush();
+        } catch (Error er) {
+            throw new ServerError(
+                    "Error occured while marshalling return value", er);
+        }
+    }
+
+    /**
+     * Loads stub class for the given remote class.
+     *
+     * @param c Class whose stub should be loaded
+     * @param throwException should we throw StubNotFoundException in case of
+     *        failure or silently return null
+     *
+     * @return loaded stub or null if throwException is false and any failure
+     *         occured during stub loading
+     *
+     * @throws StubNotFoundException if throwException parameter is true and any
+     *         failure occured during stub loading
+     */
+    protected Class loadStubClass(Class c, boolean throwException)
+            throws StubNotFoundException {
+        String stubName = c.getName() + "_Stub";
+        ClassLoader cl = c.getClassLoader();
+
+        try {
+            if (cl != null) {
+                return cl.loadClass(stubName);
+            } else {
+                return Class.forName(stubName);
+            }
+        } catch (ClassNotFoundException cnfe) {
+            if (throwException) {
+                throw new StubNotFoundException(
+                        "Stub " + stubName + " not found.", cnfe);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Loads and instantiates skel class for the given remote class.
+     *
+     * @param c Class whose skel should be loaded and instantiated
+     *
+     * @return created skel class or null if any Exception occured during
+     *         skel loading or instantiating
+     */
+    protected Skeleton getSkelInstance(Class c) {
+        String skelName = c.getName() + "_Skel";
+        ClassLoader cl = c.getClassLoader();
+
+        try {
+            Class skelClass;
+
+            if (cl != null) {
+                skelClass = cl.loadClass(skelName);
+            } else {
+                skelClass = Class.forName(skelName);
+            }
+            return (Skeleton) skelClass.newInstance();
+        } catch (Exception ex) {
+        }
+        return null;
+    }
+
+    /**
+     * Creates client-side reference holding the given Endpoint and Object ID.
+     *
+     * @param ep Endpoint for UnicastRef creation
+     * @param objId Object ID for UnicastRef creation
+     *
+     * @return created client-sice reference
+     */
+    protected UnicastRef getClientRef(Endpoint ep, ObjID objId) {
+        if (ep.getClientSocketFactory() == null) {
+            return new UnicastRef(ep, objId, true);
+        } else {
+            return new UnicastRef2(ep, objId, true);
+        }
+    }
+
+    // Reads parameters for the given method from the specified InputStream.
+    private Object[] readParams(Method m, RMIObjectInputStream oin)
+            throws RemoteException {
+        Class[] paramTypes = m.getParameterTypes();
+        Object[] params = new Object[paramTypes.length];
+
+        try {
+            for (int i = 0; i < paramTypes.length; ++i) {
+                params[i] = oin.readRMIObject(paramTypes[i],
+                        paramTypes[i].getClassLoader());
+            }
+        } catch (RemoteException re) {
+            throw new ServerException(
+                    "RemoteException occured while unmarshalling arguments",
+                    re);
+        } catch (IOException ioe) {
+            throw new UnmarshalException(
+                    "IOException occured while unmarshalling arguments", ioe);
+        } catch (ClassNotFoundException cnfe) {
+            throw new UnmarshalException("ClassNotFoundException occured while "
+                    + "unmarshalling arguments", cnfe);
+        } catch (Error er) {
+            throw new ServerError(
+                    "Error occured while unmarshalling arguments", er);
+        }
+        return params;
+    }
+
+    /*
+     * Prepares Exception to be sent to client as a result of remote method
+     * call.
+     *
+     * @param m Method string representation which cause the exception
+     * @param t Throwable to be processed.
+     *
+     * @return prepared Exception
+     */
+    private Exception prepareException(String m, Throwable t) {
+        Throwable preparedEx = null;
+        logServerException(m, t);
+
+        if (t instanceof Error) {
+            preparedEx = new ServerError(
+                    "Error occured while remote method invocation", (Error) t);
+        } else if (t instanceof RemoteException) {
+            preparedEx = new ServerException("RemoteException occured "
+                    + "while remote method invocation",
+                    (RemoteException) t);
+        } else {
+            preparedEx = t;
+        }
+        Exception toReturn = (Exception) preparedEx;
+
+        if (suppressST) {
+            // clear stack traces
+            StackTraceElement[] emptyST = new StackTraceElement[0];
+
+            for (; preparedEx != null; preparedEx = preparedEx.getCause()) {
+                preparedEx.setStackTrace(emptyST);
+            }
+        }
+        return toReturn;
+    }
+
+    // Logs remote method call.
+    private void logServerCall(String m) {
+        if (serverCallsLog.isLoggable(RMILog.VERBOSE)) {
+            String client = ServerConnectionManager.getClientHost();
+
+            if (client != null) {
+                client = "Remote call from [" + client + "]";
+            } else {
+                client = "Local remote call";
+            }
+            serverCallsLog.log(RMILog.VERBOSE,
+                    client + ": method:[" + m + "], class:["
+                    + implClassName + "].");
+        }
+    }
+
+    // Logs Exception thrown by remote method call.
+    private void logServerException(String m, Throwable t) {
+        if (printST || serverCallsLog.isLoggable(RMILog.BRIEF)) {
+            String client = ServerConnectionManager.getClientHost();
+
+            if (client != null) {
+                client = "from " + client;
+            } else {
+                client = "locally";
+            }
+            String logMsg = "Exception thrown while calling [" + m
+                    + "] method of " + implClassName
+                    + " class requested " + client + ":";
+
+            if (printST) {
+                synchronized (System.err) {
+                    System.err.println(logMsg);
+                    t.printStackTrace(System.err);
+                }
+            }
+
+            if (serverCallsLog.isLoggable(RMILog.BRIEF)) {
+                serverCallsLog.log(RMILog.BRIEF,
+                        "Exception thrown while calling [" + m + "] method of "
+                        + implClassName + " class requested "
+                        + client + ":", t);
+            }
+        }
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef2.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef2.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef2.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef2.java Thu May 18 13:01:22 2006
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed 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.
+ */
+
+/**
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.2 $
+ */
+package org.apache.harmony.rmi.remoteref;
+
+import java.io.ObjectOutput;
+import java.rmi.server.ObjID;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+
+
+/**
+ * Implementation of server-side handle for remote objects using custom
+ * socket factories.
+ *
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.2 $
+ */
+public class UnicastServerRef2 extends UnicastServerRef {
+
+    private static final long serialVersionUID = -3460099617464801595L;
+
+    /**
+     * Constructs default UnicastServerRef2 listening on anonymous port and
+     * using default client and server socket factories.
+     */
+    public UnicastServerRef2() {
+        super();
+    }
+
+    /**
+     * Constructs UnicastServerRef2 listening on the port specified and
+     * having the given client and server socket factories.
+     *
+     * @param port port where this UnicastServerRef2 will listen for connections
+     * @param csf client-side socket factory for creating client sockets
+     * @param ssf server-side socket factory for creating server sockets
+     */
+    public UnicastServerRef2(int port,
+                            RMIClientSocketFactory csf,
+                            RMIServerSocketFactory ssf) {
+        this(port, csf, ssf, new ObjID());
+    }
+
+    /**
+     * Constructs UnicastServerRef2 listening on the port specified,
+     * using specified client and server socket factories and
+     * having the given ObjID.
+     *
+     * @param port port where this UnicastServerRef2 will listen for connections
+     * @param csf client-side socket factory for creating client sockets
+     * @param ssf server-side socket factory for creating server sockets
+     * @param objId Object ID of remote object
+     */
+    public UnicastServerRef2(int port,
+                             RMIClientSocketFactory csf,
+                             RMIServerSocketFactory ssf,
+                             ObjID objId) {
+        super(port, csf, ssf, objId);
+    }
+
+    /**
+     * @see RemoteRef.getRefClass(ObjectOutput)
+     */
+    public String getRefClass(ObjectOutput out) {
+        return "UnicastServerRef2";
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/UnicastServerRef2.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/package.html
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/package.html?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/package.html (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/package.html Thu May 18 13:01:22 2006
@@ -0,0 +1,25 @@
+<html>
+<!--
+Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+
+Licensed 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.
+-->
+<!--
+Author:  Vasily Zakharov
+Version: $Revision: 1.1.2.1 $
+-->
+<body>
+Remote reference implementation classes.
+</body>
+</html>

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/remoteref/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ClientDGC.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ClientDGC.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ClientDGC.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ClientDGC.java Thu May 18 13:01:22 2006
@@ -0,0 +1,567 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed 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.
+ */
+
+/**
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.3 $
+ */
+package org.apache.harmony.rmi.server;
+
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.rmi.RemoteException;
+import java.rmi.dgc.DGC;
+import java.rmi.dgc.Lease;
+import java.rmi.dgc.VMID;
+import java.rmi.server.ObjID;
+import java.rmi.server.RemoteRef;
+import java.rmi.server.UID;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.Vector;
+
+import org.apache.harmony.rmi.common.CreateThreadAction;
+import org.apache.harmony.rmi.common.GetLongPropAction;
+import org.apache.harmony.rmi.common.InterruptThreadAction;
+import org.apache.harmony.rmi.common.RMIProperties;
+import org.apache.harmony.rmi.remoteref.UnicastRef;
+import org.apache.harmony.rmi.transport.Endpoint;
+
+
+/**
+ * DGC on Client's side - it's responsible for renewing/cancelling
+ * remote objects leases.
+ * It is made package protected for security reasons.
+ *
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.3 $
+ */
+class ClientDGC {
+
+    /** ObjID for DGC. */
+    public static final ObjID DGC_ID = new ObjID(ObjID.DGC_ID);
+
+    /*
+     * DGC ack timeout (in ms.) during which we hold strong refs to the objects.
+     * Default value is 300000 ms (5 minutes).
+     */
+    private static final long dgcAckTimeout =
+        ((Long) AccessController.doPrivileged(
+                new GetLongPropAction(RMIProperties.DGCACKTIMEOUT_PROP,
+                        5 * 60 * 1000))).longValue();
+    /*
+     * Max length of time (in ms.) between DGC.clean() calls in case of failed
+     * calls. Default value is 180000 ms (3 minutes).
+     */
+    private static final long cleanInterval =
+        ((Long) AccessController.doPrivileged(
+                new GetLongPropAction(RMIProperties.DGCCLEANINTERVAL_PROP,
+                        3 * 60 * 1000))).longValue();
+
+    // VMID for this VM
+    private static final VMID vmid = new VMID();
+
+    /*
+     * Sequentially increasing number for DGC calls.
+     * It should be accessed vid getSeqNumber() method only.
+     */
+    private static long seqNum = Long.MIN_VALUE;
+
+    // Table where Endpoint's are keys and RenewInfo are values.
+    private static Hashtable epTable = new Hashtable();
+
+    // List of strong refs to remoteObjects for referencing during DGC ack call.
+    private static Hashtable dgcAckTable = new Hashtable();
+
+    // Thread renewing leases.
+    private static Thread lRenewer;
+
+    // Thread detecting object which were garbage-collected.
+    private static Thread roDetector = (Thread) AccessController.doPrivileged(
+            new CreateThreadAction(new RemovedObjectsDetector(),
+                    "RemovedObjectsDetector", true));
+
+    // Timer handling events waiting for DGC ack messages.
+    private static final Timer dgcAckTimer =
+            (Timer) AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    return new Timer(true);
+                }});
+
+    // DGC stub class
+    private static Class dgcStubClass;
+
+    // Queue for handling already collected objects.
+    private static ReferenceQueue collectedQueue = new ReferenceQueue();
+
+    static {
+
+        // Initialize DGC implementation stub-class.
+        try {
+            dgcStubClass = Class.forName(
+                "org.apache.harmony.rmi.server.DGCImpl_Stub");
+        } catch (Exception ex) {
+            throw new Error("Unable to initialize ClientDGC.", ex);
+        }
+
+        // Start the thread detecting garbage-collected objects.
+        roDetector.start();
+    }
+
+    /*
+     * Registers the given RemoteRef in the table for sending DGC.dirty() calls
+     * to the server, exported this object.
+     */
+    static void registerForRenew(RemoteRefBase ref) {
+        RenewInfo info = (RenewInfo) epTable.get(ref.ep);
+
+        if (info == null) {
+            info = new RenewInfo(ref.ep);
+            info.renewTime = System.currentTimeMillis();
+            epTable.put(ref.ep, info);
+            info.addToDirtySet(ref);
+        } else if (info.addToDirtySet(ref)) {
+            info.renewTime = System.currentTimeMillis();
+        }
+
+        if (lRenewer == null) {
+            (lRenewer = (Thread) AccessController.doPrivileged(
+                    new CreateThreadAction(new LeaseRenewer(),
+                            "LeaseRenewer", true))).start();
+        }
+    }
+
+    /*
+     * Remove the given id for the specified Endpoint from the table and call
+     * DGC.clean() method.
+     */
+    static void unregisterForRenew(Endpoint ep, ObjID id) {
+        RenewInfo info = (RenewInfo) epTable.get(ep);
+
+        if (info == null) {
+            return;
+        }
+
+        // add ObjID to the list for DGC.clean() calls
+        info.addToCleanSet(id);
+    }
+
+    /*
+     * Adds the given object to the list of strong references associated with
+     * the given UID.
+     */
+    static void registerForDGCAck(UID uid, Object obj) {
+        RemoveTask task = (RemoveTask) dgcAckTable.get(uid);
+
+        if (task == null) {
+            task = new RemoveTask(uid);
+            dgcAckTable.put(uid, task);
+            dgcAckTimer.schedule(task, dgcAckTimeout);
+        }
+        task.addStrongRef(obj);
+    }
+
+    /*
+     * Removes all strong refs associated with the given UID.
+     */
+    static void unregisterForDGCAck(UID uid) {
+        TimerTask task = (TimerTask) dgcAckTable.get(uid);
+
+        if (task == null) {
+            return;
+        }
+        task.cancel();
+        dgcAckTable.remove(uid);
+    }
+
+    /*
+     * Returns next sequence number
+     */
+    private static synchronized long getSeqNumber() {
+        return seqNum++;
+    }
+
+
+    /*
+     * Auxiliary class for removing strong refs to the objects from the table.
+     */
+    private static class RemoveTask extends TimerTask {
+        // UID for removing from the table
+        private UID uid;
+
+        // strong references to the objects
+        private List strongRefs = new Vector();
+
+        /*
+         * Constructs RemoveTask for removing the given UID from the table.
+         *
+         * @param uid UID to be removed in the future by this task
+         */
+        RemoveTask(UID uid) {
+            this.uid = uid;
+        }
+
+        /*
+         * Removes strong refs to the objects associated with the stored UID
+         * from the table;
+         */
+        public void run() {
+            dgcAckTable.remove(uid);
+        }
+
+        /*
+         * Adds strong ref to the given object to the list.
+         *
+         * @param obj Object strong reference to which should be stored
+         */
+        void addStrongRef(Object obj) {
+            strongRefs.add(obj);
+        }
+    }
+
+
+    /*
+     * Phantom reference holding Endpoint and ObjID information for cancelling
+     * leases after object is garbage-collected.
+     */
+    private static class PhantomRef extends PhantomReference {
+        private Endpoint ep;
+        private ObjID id;
+
+        /*
+         * Constructs PhantomRef. Calls super() with the given queue and obj and
+         * stores ep and id.
+         */
+        PhantomRef(Object obj,
+                   ReferenceQueue queue,
+                   Endpoint ep,
+                   ObjID id) {
+            super(obj, queue);
+            this.ep = ep;
+            this.id = id;
+        }
+    }
+
+
+    /*
+     * Auxiliary class holding all info needed for leases renewing.
+     */
+    private static class RenewInfo {
+
+        /*
+         * Remote Endpoint where leases should be renewed.
+         */
+        private Endpoint ep;
+
+        /*
+         * Table where objIDs whose leases should be renewed are the keys
+         * and PhantomRefs are the values.
+         */
+        private Hashtable renewTable = new Hashtable();
+
+        /*
+         * Table where objIDs whose leases should be cancelled are stored
+         */
+        private Set cleanSet = Collections.synchronizedSet(new HashSet());
+
+        // Object for tables synchronization.
+        private Object tablesLock = new Object();
+
+        // When to renew leases.
+        private long renewTime;
+
+        // Initialized DGC stub.
+        private DGC dgcStub;
+
+        // Thread calling DGC.clean method
+        private Thread cleanCaller = null;
+
+        // Time when the first DGC.dirty call failed
+        private long failureStartTime = 0;
+
+        // Number of failed DGC.dirty calls.
+        private int failedDirtyCallsNum = 0;
+
+        // Base time for calculating renew time in case of failed dirty calls
+        private long failedRenewBaseDuration = 0;
+
+        // Lease duration returned by the latest successfull DGC.dirty call.
+        private long latestLeaseDuration = 0;
+
+        /*
+         * Initializes DGC stub and stores the given Endpoint.
+         *
+         * @param ep RemoteEndpoint where leases should be renewed
+         */
+        RenewInfo(Endpoint ep) {
+            this.ep = ep;
+            try {
+                dgcStub = (DGC) dgcStubClass.getConstructor(
+                        new Class[] { RemoteRef.class }).newInstance(
+                                new Object[] { new UnicastRef(ep, DGC_ID) });
+            } catch (Exception ex) {
+                throw new Error("Unable to initialized DGC stub.", ex);
+            }
+        }
+
+        /*
+         * Calls DGC.dirty() method.
+         */
+        void dgcDirty() {
+            ObjID[] ids;
+
+            synchronized (tablesLock) {
+                ids = (ObjID[]) renewTable.keySet().toArray(
+                        new ObjID[renewTable.size()]);
+            }
+
+            try {
+                Lease lease = dgcStub.dirty(ids, getSeqNumber(),
+                        new Lease(vmid, DGCImpl.maxDuration));
+                failedDirtyCallsNum = 0;
+                failureStartTime = 0;
+                latestLeaseDuration = lease.getValue();
+                renewTime = System.currentTimeMillis()
+                        + latestLeaseDuration / 2;
+            } catch (RemoteException re) {
+                // dirty call failed
+                long curTime = System.currentTimeMillis();
+                ++failedDirtyCallsNum;
+
+                if (failedDirtyCallsNum == 1) {
+                    failureStartTime = curTime;
+                    latestLeaseDuration = (latestLeaseDuration > 0)
+                            ? latestLeaseDuration : DGCImpl.maxDuration;
+                    failedRenewBaseDuration = latestLeaseDuration >> 5;
+                }
+                renewTime = curTime +
+                    failedRenewBaseDuration * ((failedDirtyCallsNum - 1) << 1);
+
+                if (renewTime > failureStartTime + latestLeaseDuration) {
+                    renewTime = Long.MAX_VALUE;
+                }
+            }
+        }
+
+        /*
+         * Adds ObjID of the given ref to the set of objIDs whose leases should
+         * be renewed, creates a PhantomReference for the object for sending
+         * clean request to the server's DGC when the object is
+         * garbage-collected.
+         *
+         * @param ref UnicastRef to be registered
+         *
+         * @return true if this RenewInfo already contained the given ref and
+         *         false otherwise
+         */
+        boolean addToDirtySet(RemoteRefBase ref) {
+            synchronized (tablesLock) {
+                ObjID id = ref.getObjId();
+
+                if (renewTable.containsKey(id)) {
+                    return true;
+                }
+                renewTable.put(id, new PhantomRef(
+                        ref, collectedQueue, ep, id));
+                return false;
+            }
+        }
+
+        /*
+         * Adds the given ObjID to the list of objects for DGC.clean() method
+         * call and removes it from the dirty set.
+         *
+         * @param id ObjID of remote object
+         */
+        void addToCleanSet(ObjID id) {
+            synchronized (tablesLock) {
+                renewTable.remove(id);
+                cleanSet.add(id);
+
+                if (cleanCaller == null) {
+                    (cleanCaller = ((Thread) AccessController.doPrivileged(
+                            new CreateThreadAction(new CleanCaller(this),
+                                    "CleanCaller for " + ep, true)))).start();
+                } else {
+                    AccessController.doPrivileged(
+                            new InterruptThreadAction(cleanCaller));
+                }
+            }
+        }
+    }
+
+
+    /*
+     * Auxiliary class renewing leases.
+     */
+    private static class LeaseRenewer implements Runnable {
+        /**
+         * Iterates over epTable and renews leases.
+         */
+        public void run() {
+            do {
+                long curTime = System.currentTimeMillis();
+                long awakeTime = curTime + DGCImpl.maxDuration / 2;
+
+                try {
+                    synchronized (epTable) {
+                        for (Enumeration eps = epTable.keys();
+                                eps.hasMoreElements();) {
+                            Endpoint ep = (Endpoint) eps.nextElement();
+                            RenewInfo info = (RenewInfo) epTable.get(ep);
+
+                            if (info.renewTime <= curTime) {
+                                // we should renew lease for this ids
+                                info.dgcDirty();
+                            }
+
+                            if (info.renewTime < awakeTime) {
+                                awakeTime = info.renewTime;
+                            }
+                        }
+                    }
+
+                    if (awakeTime > curTime) {
+                        Thread.sleep(awakeTime - curTime);
+                    }
+                } catch (InterruptedException ie) {
+                }
+            } while (epTable.size() != 0);
+            lRenewer = null;
+        }
+    }
+
+
+    /*
+     * Auxiliary thread detecting remote objects which where garbage-collected
+     * and spawning the thread callling DGC.clean() method.
+     */
+    private static class RemovedObjectsDetector implements Runnable {
+
+        /**
+         * Thread sitting on blocking ReferenceQueue.remove() method and when
+         * it returns PhantomRef - removing the object from the dirty set and
+         * calling DGC.clean() method.
+         */
+        public void run() {
+            do {
+                try {
+                    // this operation blocks the thread
+                    PhantomRef ref = (PhantomRef) collectedQueue.remove();
+
+                    unregisterForRenew(ref.ep, ref.id);
+                } catch (InterruptedException ie) {
+                }
+            } while (true);
+        }
+    }
+
+
+    /*
+     * Auxiliary class calling DGC.clean() method on server side.
+     */
+    private static class CleanCaller implements Runnable {
+        // RenewInfo where this class was created
+        private RenewInfo info;
+
+        // Number of failed DGC.clean calls.
+        private int failedCleanCallsNum = 0;
+
+        /*
+         * Constructs CleanCaller holding the reference to the given RenewInfo.
+         */
+        CleanCaller(RenewInfo info) {
+            this.info = info;
+        }
+
+        /**
+         * Call DGC.clean() method, in case of failed call retry it in a loop.
+         */
+        public void run() {
+            while (true) {
+                boolean success = true;
+                Set curCleanSet;
+
+                synchronized (info.tablesLock) {
+                    if (info.cleanSet.isEmpty()) {
+                        break;
+                    }
+                    curCleanSet = new HashSet(info.cleanSet);
+                }
+
+                try {
+                    info.dgcStub.clean((ObjID[]) curCleanSet.toArray(
+                            new ObjID[curCleanSet.size()]), getSeqNumber(),
+                            vmid, info.failedDirtyCallsNum == 0);
+
+                    // DGC.clean() call succeeded
+                    synchronized (info.tablesLock) {
+                        info.cleanSet.remove(curCleanSet);
+
+                        if (info.cleanSet.isEmpty()) {
+                            break;
+                        }
+                    }
+                } catch(RemoteException re) {
+                    // DGC.clean() call failed
+                    success = false;
+                    failedCleanCallsNum++;
+
+                    if (failedCleanCallsNum > 4) {
+                        synchronized (info.tablesLock) {
+                            if (!info.renewTable.isEmpty()) {
+                                info.cleanSet.clear();
+                            }
+                        }
+                        break;
+                    }
+                }
+
+                if (Thread.interrupted()) {
+                    continue;
+                }
+
+                /*
+                 * If DGC.clean() call failed we should wait for a cleanInterval
+                 * period of time.
+                 */
+                if (!success) {
+                    try {
+                        Thread.sleep(cleanInterval);
+                    } catch(InterruptedException ie) {
+                        continue;
+                    }
+                }
+            }
+
+            synchronized (info.tablesLock) {
+                if (!info.renewTable.isEmpty()) {
+                    epTable.remove(info.ep);
+                }
+            }
+            info.cleanCaller = null;
+        }
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ClientDGC.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl.java Thu May 18 13:01:22 2006
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed 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.
+ */
+
+/**
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.2 $
+ */
+package org.apache.harmony.rmi.server;
+
+import java.rmi.RemoteException;
+import java.rmi.dgc.DGC;
+import java.rmi.dgc.Lease;
+import java.rmi.dgc.VMID;
+import java.rmi.server.ObjID;
+import java.security.AccessController;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.harmony.rmi.common.CreateThreadAction;
+import org.apache.harmony.rmi.common.GetLongPropAction;
+import org.apache.harmony.rmi.common.RMILog;
+import org.apache.harmony.rmi.common.RMIProperties;
+
+
+/**
+ * Distributed Garbage Collector implementation (Server side).
+ * It is made package protected for security reasons.
+ *
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.2 $
+ */
+class DGCImpl implements DGC {
+
+    /* Log where to write dgc activity. */
+    static final RMILog dgcLog = RMILog.getDGCLog();
+
+    /*
+     * Maximum lease duration granted by this DGC.
+     * Default value is 10 minutes.
+     */
+    static final long maxDuration =
+        ((Long) AccessController.doPrivileged(
+                new GetLongPropAction(RMIProperties.DGCLEASEVALUE_PROP,
+                        10 * 60 * 1000))).longValue();
+
+    /*
+     * How often we will check DGC leases.
+     * Default value is half of maxDuration time.
+     */
+    private static final long checkInterval =
+        ((Long) AccessController.doPrivileged(
+                new GetLongPropAction(RMIProperties.DGCCHECKINTERVAL_PROP,
+                        maxDuration / 2))).longValue();
+
+    /*
+     * Table where VMIDs are keys and HashSets of ObjIDs are the values.
+     */
+    private Hashtable vmidTable = new Hashtable();
+
+
+    // Thread checking leases expirations.
+    private static Thread expTracker;
+
+    /**
+     * @see DGC.dirty(ObjID[], long, Lease)
+     */
+    public Lease dirty(ObjID[] ids, long seqNum, Lease lease)
+            throws RemoteException {
+        VMID vmid = lease.getVMID();
+
+        if (vmid == null) {
+            vmid = new VMID();
+
+            if (dgcLog.isLoggable(RMILog.VERBOSE)) {
+                dgcLog.log(RMILog.VERBOSE, "Created new VMID: " + vmid);
+            }
+        }
+        long duration = lease.getValue();
+        if (duration > maxDuration || duration < 0) {
+            duration = maxDuration;
+        }
+        Lease l = new Lease(vmid, duration);
+
+        synchronized (vmidTable) {
+            Set s = (Set) vmidTable.get(vmid);
+
+            if (s == null) {
+                if (ids == null || ids.length == 0) {
+                    // Nothing to do: no VM with such VMID registered
+                    return l;
+                }
+                s = Collections.synchronizedSet(new HashSet());
+                vmidTable.put(vmid, s);
+            }
+
+            if (expTracker == null) {
+                (expTracker = (Thread) AccessController.doPrivileged(
+                        new CreateThreadAction(new ExpirationTracker(),
+                                "ExpirationTracker", true))).start();
+            }
+
+            for (int i = 0; i < ids.length; ++i) {
+                s.add(ids[i]);
+
+                if (dgcLog.isLoggable(RMILog.VERBOSE)) {
+                    dgcLog.log(RMILog.VERBOSE, "Added " + ids[i]
+                            + ", " + vmid + ", duration = " + duration);
+                }
+            }
+
+            for (Iterator allIds = s.iterator(); allIds.hasNext();) {
+                RMIObjectInfo info = ExportManager.getInfo(
+                        (ObjID) allIds.next());
+
+                if (info == null) {
+                    /*
+                     * Object with this id has not been exported or has been
+                     * garbage-collected.
+                     */
+                    allIds.remove();
+                    continue;
+                }
+                info.dgcDirty(vmid, seqNum, duration);
+            }
+        }
+
+        if (dgcLog.isLoggable(RMILog.VERBOSE)) {
+            dgcLog.log(RMILog.VERBOSE, "Updated " + vmid);
+        }
+        return l;
+    }
+
+    /**
+     * @see DGC.clean(ObjID[], long, VMID, boolean)
+     */
+    public void clean(ObjID[] ids, long seqNum, VMID vmid, boolean strong)
+            throws RemoteException {
+        synchronized (vmidTable) {
+            Set s = (Set) vmidTable.get(vmid);
+
+            if (s == null) {
+                return;
+            }
+
+            if (ids != null && ids.length > 0) {
+                for (int i = 0; i < ids.length; ++i) {
+                    RMIObjectInfo info = ExportManager.getInfo(ids[i]);
+
+                    if (info == null || info.dgcClean(vmid, seqNum, strong)) {
+                        s.remove(ids[i]);
+
+                        if (dgcLog.isLoggable(RMILog.VERBOSE)) {
+                            dgcLog.log(RMILog.VERBOSE, "Removed " + ids[i]
+                                    + ", " + vmid);
+                        }
+                    }
+                }
+            } else {
+                for (Iterator allIds = s.iterator(); allIds.hasNext();) {
+                    RMIObjectInfo info = ExportManager.getInfo(
+                            (ObjID) allIds.next());
+
+                    if (info == null || info.dgcClean(vmid, seqNum, strong)) {
+                        allIds.remove();
+                    }
+                }
+            }
+
+            if (s.isEmpty()) {
+                vmidTable.remove(vmid);
+
+                if (dgcLog.isLoggable(RMILog.VERBOSE)) {
+                    dgcLog.log(RMILog.VERBOSE, "Removed " + vmid);
+                }
+            }
+        }
+    }
+
+
+    /*
+     * Auxiliary class checking expiration times and removind expired entries
+     * from the list of active objects.
+     */
+    private class ExpirationTracker implements Runnable {
+        /**
+         * Checks expiration times until no objects left in the table.
+         * Sleeps for a checkInterval period of time between checks.
+         */
+        public void run() {
+            do {
+                try {
+                    Thread.sleep(checkInterval);
+                } catch (InterruptedException ie) {
+                }
+            } while (checkExpiration());
+            expTracker = null;
+        }
+
+        /*
+         * Checks expiration times and removes expired entries
+         * from the list of active objects.
+         *
+         * @return false if there are no objects in the table left and false
+         *         otherwise
+         */
+        boolean checkExpiration() {
+            if (vmidTable.size() == 0) {
+                return false;
+            }
+            long curTime = System.currentTimeMillis();
+
+            synchronized (vmidTable) {
+                for (Enumeration en = vmidTable.keys(); en.hasMoreElements();) {
+                    VMID vmid = (VMID) en.nextElement();
+                    Set s = (Set) vmidTable.get(vmid);
+
+                    for (Iterator iter = s.iterator(); iter.hasNext();) {
+                        RMIObjectInfo info = ExportManager.getInfo(
+                                (ObjID) iter.next());
+
+                        if (info == null || info.dgcClean(vmid)) {
+                            iter.remove();
+
+                            if (info != null
+                                    && dgcLog.isLoggable(RMILog.VERBOSE)) {
+                                dgcLog.log(RMILog.VERBOSE, "Lease for "
+                                        + info.id + ", " + vmid + " expired.");
+                            }
+                        }
+                    }
+                }
+            }
+            return true;
+        }
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Skel.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Skel.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Skel.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Skel.java Thu May 18 13:01:22 2006
@@ -0,0 +1,104 @@
+/*
+ * RMI skeleton class
+ * for class org.apache.harmony.rmi.server.DGCImpl
+ * Compatible with stub protocol version 1.1
+ *
+ * Generated by DRL RMI Compiler (rmic).
+ *
+ * DO NOT EDIT!!!
+ * Contents subject to change without notice!
+ */
+package org.apache.harmony.rmi.server;
+
+
+public final class DGCImpl_Skel implements java.rmi.server.Skeleton {
+
+    private static final long interfaceHash = -669196253586618813L;
+
+    private static final java.rmi.server.Operation[] operations = {
+        new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"),
+        new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)")
+    };
+
+    public java.rmi.server.Operation[] getOperations() {
+        return (java.rmi.server.Operation[]) operations.clone();
+    }
+
+    public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception {
+        if (hash != interfaceHash) {
+            throw new java.rmi.server.SkeletonMismatchException(
+                    "Interface hash mismatch, expected: " + interfaceHash + ", received: " + hash);
+        }
+
+        org.apache.harmony.rmi.server.DGCImpl server = (org.apache.harmony.rmi.server.DGCImpl) obj;
+
+        switch (opnum) {
+
+        case 0: {    // clean(ObjID[], long, VMID, boolean)
+
+            java.rmi.server.ObjID[] $param_arrayOf_ObjID_1;
+            long $param_long_2;
+            java.rmi.dgc.VMID $param_VMID_3;
+            boolean $param_boolean_4;
+
+            try {
+                java.io.ObjectInput in = call.getInputStream();
+                $param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
+                $param_long_2 = in.readLong();
+                $param_VMID_3 = (java.rmi.dgc.VMID) in.readObject();
+                $param_boolean_4 = in.readBoolean();
+            } catch (java.io.IOException e) {
+                throw new java.rmi.UnmarshalException("Error unmarshalling arguments", e);
+            } catch (java.lang.ClassNotFoundException e) {
+                throw new java.rmi.UnmarshalException("Error unmarshalling arguments", e);
+            } finally {
+                call.releaseInputStream();
+            }
+
+            server.clean($param_arrayOf_ObjID_1, $param_long_2, $param_VMID_3, $param_boolean_4);
+
+            try {
+                call.getResultStream(true);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("Error marshalling return", e);
+            }
+
+            break;
+        }
+
+        case 1: {    // dirty(ObjID[], long, Lease)
+
+            java.rmi.server.ObjID[] $param_arrayOf_ObjID_1;
+            long $param_long_2;
+            java.rmi.dgc.Lease $param_Lease_3;
+
+            try {
+                java.io.ObjectInput in = call.getInputStream();
+                $param_arrayOf_ObjID_1 = (java.rmi.server.ObjID[]) in.readObject();
+                $param_long_2 = in.readLong();
+                $param_Lease_3 = (java.rmi.dgc.Lease) in.readObject();
+            } catch (java.io.IOException e) {
+                throw new java.rmi.UnmarshalException("Error unmarshalling arguments", e);
+            } catch (java.lang.ClassNotFoundException e) {
+                throw new java.rmi.UnmarshalException("Error unmarshalling arguments", e);
+            } finally {
+                call.releaseInputStream();
+            }
+
+            java.rmi.dgc.Lease $result = server.dirty($param_arrayOf_ObjID_1, $param_long_2, $param_Lease_3);
+
+            try {
+                java.io.ObjectOutput out = call.getResultStream(true);
+                out.writeObject($result);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("Error marshalling return", e);
+            }
+
+            break;
+        }
+
+        default:
+            throw new java.rmi.UnmarshalException("Invalid method number: " + opnum);
+        }
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Skel.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Stub.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Stub.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Stub.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Stub.java Thu May 18 13:01:22 2006
@@ -0,0 +1,99 @@
+/*
+ * RMI stub class
+ * for class org.apache.harmony.rmi.server.DGCImpl
+ * Compatible with stub protocol version 1.1
+ *
+ * Generated by DRL RMI Compiler (rmic).
+ *
+ * DO NOT EDIT!!!
+ * Contents subject to change without notice!
+ */
+package org.apache.harmony.rmi.server;
+
+
+public final class DGCImpl_Stub extends java.rmi.server.RemoteStub
+        implements java.rmi.dgc.DGC {
+
+    private static final long interfaceHash = -669196253586618813L;
+
+    private static final java.rmi.server.Operation[] operations = {
+        new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"),
+        new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)")
+    };
+
+    public DGCImpl_Stub() {
+        super();
+    }
+
+    public DGCImpl_Stub(java.rmi.server.RemoteRef ref) {
+        super(ref);
+    }
+
+    // Implementation of clean(ObjID[], long, VMID, boolean)
+    public void clean(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.VMID $param_VMID_3, boolean $param_boolean_4)
+            throws java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
+
+            try {
+                java.io.ObjectOutput out = call.getOutputStream();
+                out.writeObject($param_arrayOf_ObjID_1);
+                out.writeLong($param_long_2);
+                out.writeObject($param_VMID_3);
+                out.writeBoolean($param_boolean_4);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("Error marshalling arguments", e);
+            }
+
+            ref.invoke(call);
+
+            ref.done(call);
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("Undeclared checked exception", e);
+        }
+    }
+
+    // Implementation of dirty(ObjID[], long, Lease)
+    public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_arrayOf_ObjID_1, long $param_long_2, java.rmi.dgc.Lease $param_Lease_3)
+            throws java.rmi.RemoteException {
+        try {
+            java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
+
+            try {
+                java.io.ObjectOutput out = call.getOutputStream();
+                out.writeObject($param_arrayOf_ObjID_1);
+                out.writeLong($param_long_2);
+                out.writeObject($param_Lease_3);
+            } catch (java.io.IOException e) {
+                throw new java.rmi.MarshalException("Error marshalling arguments", e);
+            }
+
+            ref.invoke(call);
+
+            java.rmi.dgc.Lease $result;
+
+            try {
+                java.io.ObjectInput in = call.getInputStream();
+                $result = (java.rmi.dgc.Lease) in.readObject();
+            } catch (java.io.IOException e) {
+                throw new java.rmi.UnmarshalException("Error unmarshalling return value", e);
+            } catch (java.lang.ClassNotFoundException e) {
+                throw new java.rmi.UnmarshalException("Error unmarshalling return value", e);
+            } finally {
+                ref.done(call);
+            }
+
+            return $result;
+        } catch (java.lang.RuntimeException e) {
+            throw e;
+        } catch (java.rmi.RemoteException e) {
+            throw e;
+        } catch (java.lang.Exception e) {
+            throw new java.rmi.UnexpectedException("Undeclared checked exception", e);
+        }
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/DGCImpl_Stub.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ExportManager.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ExportManager.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ExportManager.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ExportManager.java Thu May 18 13:01:22 2006
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors, as applicable
+ *
+ * Licensed 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.
+ */
+
+/**
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.3 $
+ */
+package org.apache.harmony.rmi.server;
+
+import java.lang.ref.ReferenceQueue;
+import java.rmi.NoSuchObjectException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.dgc.DGC;
+import java.rmi.server.ExportException;
+import java.rmi.server.ObjID;
+import java.security.AccessController;
+
+import org.apache.harmony.rmi.common.CreateThreadAction;
+import org.apache.harmony.rmi.common.InterruptThreadAction;
+import org.apache.harmony.rmi.remoteref.UnicastServerRef;
+
+
+/**
+ * Manager controlling all exported objects.
+ * It is put to org.apache.harmony.rmi.transport package because some methods
+ * should be made package protected.
+ *
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.3 $
+ */
+public class ExportManager {
+
+    // List of all remote objects exported in this VM.
+    private static RMIObjectTable exportedObjs = new RMIObjectTable();
+
+    // The only one instance of DGC per VM.
+    private static DGC dgcImpl = new DGCImpl();
+
+    // Creates and exports DGC implementation.
+    static {
+        try {
+            UnicastServerRef dgcRef = new UnicastServerRef(0, null, null,
+                    ClientDGC.DGC_ID);
+            dgcRef.exportObject(dgcImpl, null, false, false, true);
+            RMIObjectInfo dgcInfo = new RMIObjectInfo(
+                    new RMIReference(dgcImpl), ClientDGC.DGC_ID, dgcRef, null);
+            exportedObjs.add(dgcInfo);
+        } catch (Exception ex) {
+            throw new Error("Unable to initialize DGC.", ex);
+        }
+    }
+
+    // Queue to wait for objects to be collected.
+    private static ReferenceQueue dgcQueue = new ReferenceQueue();
+
+    // Thread removing GC-collected objects from the table of Exported objects.
+    private static Thread scav;
+
+    // Number of in-progress calls to the objects in this table.
+    private static int activeCallsNum = 0;
+
+    // Number of non system (requiring VM-blocking thread) objects.
+    private static int nonSystemObjsNum = 0;
+
+    // lock object for working with active calls
+    private static Object callsLock = new Object();
+
+    /**
+     * Exports specified remote object through pre-initialized UnicastServerRef.
+     * Returns info for exported object. If object has already been exported,
+     * ExportException will be thrown. The thread listening for incoming
+     * connections will be started.
+     *
+     * @param obj remote object to be exported
+     * @param sref initialized UnicastServerRef to export object through
+     * @param useProxyStubs If true then Proxy stubs will be generated if stub
+     *        class could not be found in classpath and codebase; if false Proxy
+     *        stubs will not be tried (this is needed for
+     *        UnicastRemoteObject.exportObject(Remote) method because it
+     *        returns RemoteStub class (but Proxy class could not be casted
+     *        to it)
+     *
+     * @return stub for exported object
+     *
+     * @throws RemoteException if any exception occured while exporting
+     *         specified remote object
+     */
+    public static Remote exportObject(Remote obj,
+                                      UnicastServerRef sref,
+                                      boolean useProxyStubs)
+            throws RemoteException {
+        return exportObject(obj, sref, useProxyStubs, true, false);
+    }
+
+    /**
+     * Exports specified remote object through pre-initialized UnicastServerRef.
+     * Returns info for exported object. If object has already been exported,
+     * ExportException will be thrown.
+     *
+     * @param obj remote object to be exported
+     * @param sref initialized UnicastServerRef to export object through
+     * @param useProxyStubs If true then Proxy stubs will be generated if stub
+     *        class could not be found in classpath and codebase; if false Proxy
+     *        stubs will not be tried (this is needed for
+     *        UnicastRemoteObject.exportObject(Remote) method because it
+     *        returns RemoteStub class (but Proxy class could not be casted
+     *        to it)
+     * @param startListen if false, ServerSocket listening thread will not be
+     *        started (this is used for DGC, for example); otherwise listening
+     *        thread will be started and object becomes available for
+     *        connections from clients
+     * @param isSystem if true then existence of this object will not prevent
+     *        VM from exiting (for example, for rmiregistry)
+     *
+     * @return stub for exported object
+     *
+     * @throws RemoteException if any exception occured while exporting
+     *         specified remote object
+     */
+    public static Remote exportObject(Remote obj,
+                                      UnicastServerRef sref,
+                                      boolean useProxyStubs,
+                                      boolean startListen,
+                                      boolean isSystem)
+            throws RemoteException {
+        if (isExported(obj)) {
+            throw new ExportException(
+                    "Object " + obj + " has already been exported.");
+        }
+        Remote stub = sref.exportObject(obj, null, useProxyStubs, startListen,
+                isSystem);
+        RMIReference rref = new RMIReference(obj, dgcQueue);
+        RMIObjectInfo info = new RMIObjectInfo(
+                rref, sref.getObjId(), sref, stub);
+        exportedObjs.add(info);
+
+        if (scav == null) {
+            (scav = (Thread) AccessController.doPrivileged(
+                    new CreateThreadAction(new Scavenger(),
+                            "Scavenger", false))).start();
+        }
+
+        if (isSystem) {
+            rref.makeStrong(true);
+        } else {
+            ++nonSystemObjsNum;
+        }
+        return stub;
+    }
+
+    /**
+     * Unexports specified remote object so it becomes unavailable for
+     * receiving remote calls. If force parameter is false then the object will
+     * be unexported only if there are no pending or in-progress remote calls
+     * to it, otherwise (if force parameter is true) the object will be
+     * unexported forcibly.
+     *
+     * @param obj remote object to be unexported
+     * @param force if false then specified object will only be unexported if
+     *        there are no pending or in-progress calls to it; otherwise
+     *        the object will be unexported forcibly (even if there are such
+     *        calls)
+     *
+     * @throws NoSuchObjectException if specified object has not been exported
+     *         or has already been unexported
+     */
+    public static boolean unexportObject(Remote obj, boolean force)
+            throws NoSuchObjectException {
+        RMIReference ref = new RMIReference(obj);
+        RMIObjectInfo info = exportedObjs.getByRef(ref);
+
+        if (info == null) {
+            throw new NoSuchObjectException(
+                    "Object " + obj + " is not exported.");
+        }
+        boolean succeeded = info.sref.unexportObject(force);
+
+        if (succeeded) {
+            exportedObjs.removeByRef(ref);
+
+            synchronized (callsLock) {
+                if (!info.sref.isSystem()) {
+                        --nonSystemObjsNum;
+                }
+                scavInterrupt();
+            }
+        }
+        return succeeded;
+    }
+
+    /**
+     * Returns stub for specified remote object, or throws NoSuchObjectException
+     * if object was not exported via this class.
+     *
+     * @param obj remote object for which stub is needed
+     *
+     * @return stub for specified remote object if it was exported
+     *
+     * @throws NoSuchObjectException if specified object was not exported via
+     *         this class
+     */
+    public static Remote getStub(Remote obj) throws NoSuchObjectException {
+        RMIObjectInfo info = exportedObjs.getByRef(new RMIReference(obj));
+
+        if (info == null) {
+            throw new NoSuchObjectException(
+                    "Object " + obj + " is not exported.");
+        }
+        return info.stub;
+    }
+
+    /**
+     * Returns true if specified remote object was exported via this class.
+     *
+     * @param obj remote object to check
+     *
+     * @return true if specified remote object was exported via this class
+     */
+    public static boolean isExported(Remote obj) {
+        return exportedObjs.containsByRef(new RMIReference(obj));
+    }
+
+    /*
+     * Returns RMIObjectInfo in the list of exported objects using the given
+     * Object ID as a key.
+     *
+     * @param id Object ID to be used as a key
+     *
+     * @return RMIObjectInfo found
+     */
+    static RMIObjectInfo getInfo(ObjID id) {
+        return exportedObjs.getById(id);
+    }
+
+    /*
+     * Increase the number of active calls by one.
+     */
+    static void addActiveCall() {
+        synchronized (callsLock) {
+            ++activeCallsNum;
+
+            if (scav == null) {
+                (scav = (Thread) AccessController.doPrivileged(
+                        new CreateThreadAction(new Scavenger(),
+                                "Scavenger", false))).start();
+            }
+        }
+    }
+
+    /*
+     * Decrease the number of active callse by one.
+     */
+    static void removeActiveCall() {
+        synchronized (callsLock) {
+            --activeCallsNum;
+            scavInterrupt();
+        }
+    }
+
+    /*
+     * Interrupts thread removing objects from the table, if the number of
+     * active calls and number of exported system objects are both zero.
+     */
+    private static void scavInterrupt() {
+        if (activeCallsNum == 0 && nonSystemObjsNum == 0 && scav != null) {
+            AccessController.doPrivileged(new InterruptThreadAction(scav));
+            scav = null;
+        }
+    }
+
+
+    /*
+     * Thread removind objects from the table when they are scheduled for GC.
+     * It blocks VM from exiting as it's run with setDaemon(false).
+     */
+    private static class Scavenger implements Runnable {
+        public void run() {
+            try {
+                do {
+                    // this operation blocks the thread
+                    RMIReference ref = (RMIReference) dgcQueue.remove();
+
+                    // removes objects from the table
+                    RMIObjectInfo info = exportedObjs.removeByRef(ref);
+
+                    synchronized (callsLock) {
+                        if (info != null) {
+                            if (!info.sref.isSystem()) {
+                                --nonSystemObjsNum;
+                            }
+                        }
+
+                        if (nonSystemObjsNum == 0 && activeCallsNum == 0) {
+                            break;
+                        }
+                    }
+                } while (!Thread.interrupted());
+            } catch (InterruptedException ie) {
+            }
+            scav = null;
+        }
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/server/ExportManager.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message