You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by gh...@apache.org on 2006/05/18 22:01:30 UTC

svn commit: r407625 [8/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/javasrc...

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMILog.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMILog.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMILog.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMILog.java Thu May 18 13:01:22 2006
@@ -0,0 +1,431 @@
+/*
+ * 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.4 $
+ */
+package org.apache.harmony.rmi.common;
+
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.logging.LogRecord;
+import java.util.logging.SimpleFormatter;
+import java.util.logging.StreamHandler;
+
+
+/**
+ * Class containing all RMI logging functionality.
+ *
+ * @author  Mikhail A. Markov
+ * @version $Revision: 1.1.2.4 $
+ */
+public class RMILog implements RMIProperties {
+
+    /**
+     * RMI logging level corresponding to Level.OFF value.
+     */
+    public static final Level SILENT = Level.OFF;
+
+    /**
+     * RMI logging level corresponding to Level.FINE value.
+     */
+    public static final Level BRIEF = Level.FINE;
+
+    /**
+     * RMI logging level corresponding to Level.FINER value.
+     */
+    public static final Level VERBOSE = Level.FINER;
+
+    // handler for copying rmi logging messages to System.err
+    private static Handler consoleHandler =
+        (Handler) AccessController.doPrivileged(new PrivilegedAction() {
+            public Object run() {
+                Handler h = new RMIStreamHandler(System.err);
+                h.setLevel(Level.ALL);
+                return h;
+            }
+        });
+
+    // Logger wrapped in this RMI log.
+    private Logger logger;
+
+    // Handler set by setOutputStream() method.
+    private RMIStreamHandler rmiLogHandler;
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging remote calls on server side.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging remote calls on server side
+     */
+    public static RMILog getServerCallsLog() {
+        return getLog("harmony.rmi.server.call",
+                getBoolean(LOGSERVER_PROP) ? VERBOSE : SILENT);
+    }
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging remote calls on client side.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging remote calls on client side
+     */
+    public static RMILog getClientCallsLog() {
+        return getLog("harmony.rmi.client.call",
+                getBoolean(LOGCLIENT_PROP) ? VERBOSE : SILENT);
+    }
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging remote reference activity on server side.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging remote reference activity on server side
+     */
+    public static RMILog getServerRefLog() {
+        return getLog("harmony.rmi.server.ref", getString(SERVERLOGLEVEL_PROP));
+    }
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging remote reference activity on client side.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging remote reference activity on client side
+     */
+    public static RMILog getClientRefLog() {
+        return getLog("harmony.rmi.client.ref", getString(CLIENTLOGLEVEL_PROP));
+    }
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging DGC activity.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging DGC activity
+     */
+    public static RMILog getDGCLog() {
+        return getLog("harmony.rmi.dgc", getString(DGCLOGLEVEL_PROP));
+    }
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging activity of default RMIClassLoader provider.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging activity of default RMIClassLoader provider
+     */
+    public static RMILog getLoaderLog() {
+        return getLog("harmony.rmi.loader", getString(LOADERLOGLEVEL_PROP));
+    }
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging transport-layer activity.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging transport-layer activity
+     */
+    public static RMILog getTransportLog() {
+        return getLog("harmony.rmi.transport.misc",
+                getString(TRANSPORTLOGLEVEL_PROP));
+    }
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging TCP binding/connection activity.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging TCP binding/connection activity
+     */
+    public static RMILog getTcpTransportLog() {
+        return getLog("harmony.rmi.transport.tcp",
+                getString(TRANSPORTTCPLOGLEVEL_PROP));
+    }
+
+    /**
+     * Helper method.
+     * Returns RMILog for logging HTTP connections activity.
+     * If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging HTTP connections activity
+     */
+    public static RMILog getProxyTransportLog() {
+        return getLog("harmony.rmi.transport.proxy",
+                getString(TRANSPORTPROXYLOGLEVEL_PROP));
+    }
+
+    /**
+     * Helper method. Returns RMILog for logging Activation/ActivationGroup/Rmid
+     * events. If such a log does not exist, creates it.
+     *
+     * @return RMILog for logging remote calls on server side
+     */
+    public static RMILog getActivationLog() {
+        return getLog("harmony.rmi.activation", getString(ACTIVATIONLOGLEVEL_PROP));
+    }
+
+    /**
+     * Creates RMILog. Underlying logger will have the name 'loggerName'. The
+     * level for created RMILog will be equal to 'logLevel' value.
+     *
+     * @param loggerName
+     *        the name of the logger to be obtained
+     *
+     * @param logLevel
+     *        the level for RMILog: it should be one of RMI logging levels
+     *        (SILENT, BRIEF, VERBOSE or one of levels from
+     *        java.util.logging.Level class
+     */
+    public static RMILog getLog(String loggerName, String logLevel) {
+        return getLog(loggerName, parseLevelString(logLevel));
+    }
+
+    /**
+     * Creates RMILog. Underlying logger will have the name 'loggerName'. The
+     * level for created RMILog will be equal to 'logLevel' value.
+     *
+     * @param loggerName the name of the logger to be obtained
+     * @param logLevel the level for RMILog
+     */
+    public static RMILog getLog(String loggerName, final Level logLevel) {
+        final Logger logger = Logger.getLogger(loggerName);
+
+        // add handler for publishing records to System.err
+        RMILog log = (RMILog) AccessController.doPrivileged(
+                new PrivilegedAction() {
+                    public Object run() {
+
+                        if (logger.getLevel() == null
+                                || !logger.isLoggable(logLevel)) {
+                            logger.setLevel(logLevel);
+                        }
+
+                        // remove System.err stream handler to avoid
+                        // duplications
+                        logger.removeHandler(consoleHandler);
+
+                        // add System.err stream handler again
+                        logger.addHandler(consoleHandler);
+                        return new RMILog(logger);
+                    }
+                });
+        return log;
+    }
+
+    /**
+     * Parses the given string and returns the corresponding Level object.
+     * Possible values for the incoming string are one of RMI logging
+     * levels (SILENT, BRIEF, VERBOSE or one of levels from
+     * java.util.logging.Level class. If the given string is null or it could
+     * not be parsed then Level.OFF value will be returned.
+     *
+     * @param levelStr String to be parsed
+     *
+     * @return parsed Level or Level.OFF if the given string is null or an
+     *         error occured while it's parsing
+     */
+    public static Level parseLevelString(String levelStr) {
+        if (levelStr == null) {
+            return Level.OFF;
+        }
+        levelStr = levelStr.trim().toUpperCase();
+
+        if (levelStr.equals("SILENT")) {
+            return SILENT;
+        } else if (levelStr.equals("BRIEF")) {
+            return BRIEF;
+        } else if (levelStr.equals("VERBOSE")) {
+            return VERBOSE;
+        }
+        Level logLevel = Level.OFF;
+
+        try {
+            logLevel = Level.parse(levelStr);
+        } catch (IllegalArgumentException iae) {
+        }
+        return logLevel;
+    }
+
+    /*
+     * Constructs RMILog containing specified Logger.
+     *
+     * @param logger Logger for RMILog
+     */
+    private RMILog(Logger logger) {
+        this.logger = logger;
+    }
+
+    /**
+     * Checks if underlying logger whould log a message with the specified
+     * level.
+     *
+     * @param l Logging level to be checked
+     *
+     * @return true if underlying logger would log a message with
+     *         the specified level and false otherwise
+     */
+    public boolean isLoggable(Level l) {
+        return logger.isLoggable(l);
+    }
+
+    /**
+     * Logs specified message prepended by the current Thread's name
+     * with the given level to the underlying logger.
+     *
+     * @param l logging level of the message
+     * @param msg message to be logged
+     */
+    public void log(Level l, String msg) {
+        if (isLoggable(l)) {
+            String[] logSrc = getLogSource();
+            logger.logp(l, logSrc[0], logSrc[1],
+                    Thread.currentThread().getName() + ": " + msg);
+        }
+    }
+
+    /**
+     * Logs specified message prepended by the current Thread's name
+     * and Throwable object with the given level to the underlying logger.
+     *
+     * @param l logging level of the message and Throwable
+     * @param msg message to be logged
+     * @param t Throwable to be logged
+     */
+    public void log(Level l, String msg, Throwable t) {
+        if (isLoggable(l)) {
+            String[] logSrc = getLogSource();
+            logger.logp(l, logSrc[0], logSrc[1],
+                    Thread.currentThread().getName() + ": " + msg, t);
+        }
+    }
+
+    /**
+     * Adds additional handler to the underlying logger from the given
+     * OutputStream. If this method with non-null parameter was already called
+     * and thus additional handler already exists, this handler will be replaced
+     * by newly created handler.
+     * This method is intended to be used by RemoteServer.setLog() method.
+     *
+     * @param out OutputStream for additional handler. If it's null then
+     *        messages will not be logged to any additional handlers.
+     *
+     * @see RemoteServer.setLog(OutputStream)
+     */
+    public synchronized void setOutputStream(OutputStream out) {
+        if (rmiLogHandler != null) {
+            logger.removeHandler(rmiLogHandler);
+        }
+
+        if (out == null) {
+            rmiLogHandler = null;
+            return;
+        }
+
+        if (!logger.isLoggable(VERBOSE)) {
+            logger.setLevel(VERBOSE);
+        }
+
+        rmiLogHandler = new RMIStreamHandler(out);
+        rmiLogHandler.setLevel(VERBOSE);
+        logger.addHandler(rmiLogHandler);
+    }
+
+    /**
+     * Returns PrintStream where RMI logs messages.
+     * This method is intended to be used by RemoteServer.getLog() method
+     *
+     * @return PrintStream where RMI logs messages (possibly null)
+     *
+     * @see RemoteServer.getLog()
+     */
+    public synchronized PrintStream getPrintStream() {
+        return (rmiLogHandler == null) ? null : rmiLogHandler.ps;
+    }
+
+    // Reads boolean value from the given property name.
+    private static boolean getBoolean(String propName) {
+        return ((Boolean) AccessController.doPrivileged(
+                new GetBooleanPropAction(propName))).booleanValue();
+    }
+
+    // Reads string value from the given property name.
+    private static String getString(String propName) {
+        return (String) AccessController.doPrivileged(
+                new GetStringPropAction(propName));
+    }
+
+    /*
+     * Returns string containing from 2 elements: the name of the class
+     * and the name of the method from which log() method was called.
+     * It's needed for logging the name of the method from which log() method
+     * was called.
+     */
+    private String[] getLogSource() {
+        StackTraceElement[] curST = (new Exception()).getStackTrace();
+
+        // this method is called from appropriate log() method, so required
+        // source will be at 3-rd cell
+        return new String[] {
+                curST[2].getClassName(), curST[2].getMethodName() };
+    }
+
+
+    /*
+     * Handler similar to ConsoleHandler but working with arbitrary
+     * OutputStreams.
+     */
+    private static class RMIStreamHandler extends StreamHandler {
+
+        // PrintStream build from OutputStream provided to constructor
+        PrintStream ps;
+
+        /*
+         * Constructs RMIStreamHandler from the given OutputStream.
+         *
+         * @param out underlying OutputStream for this handler
+         */
+        RMIStreamHandler(OutputStream out) {
+            super(out, new SimpleFormatter());
+            ps = new PrintStream(out);
+        }
+
+        /**
+         * Publish specified LogRecord.
+         *
+         * @param rec LogRecord to be published
+         */
+        public void publish(LogRecord rec) {
+            super.publish(rec);
+            flush();
+        }
+
+        /**
+         * Flushes the underlying OutputStream.
+         */
+        public void close() {
+            flush();
+        }
+    }
+}

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

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMIProperties.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMIProperties.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMIProperties.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMIProperties.java Thu May 18 13:01:22 2006
@@ -0,0 +1,156 @@
+/*
+ * 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, Vasily Zakharov
+ * @version $Revision: 1.1.2.7 $
+ */
+package org.apache.harmony.rmi.common;
+
+
+/**
+ * Interface containing names of all supported RMI properties.
+ *
+ * @author  Mikhail A. Markov, Vasily Zakharov
+ * @version $Revision: 1.1.2.7 $
+ */
+public interface RMIProperties {
+
+    /*
+     * -------------------------------------------------------------------------
+     * java.rmi.* supported properties
+     * -------------------------------------------------------------------------
+     */
+    String ACTIVATIONPORT_PROP = "java.rmi.activation.port";
+    String DGCLEASEVALUE_PROP = "java.rmi.dgc.leaseValue";
+    String CODEBASE_PROP = "java.rmi.server.codebase";
+    String HOSTNAME_PROP = "java.rmi.server.hostname";
+    String LOGSERVER_PROP = "java.rmi.server.logCalls";
+    String RANDOMIDS_PROP = "java.rmi.server.randomIDs";
+    String USECODEBASEONLY_PROP = "java.rmi.server.usecodebaseOnly";
+    String USELOCALHOSTNAME_PROP = "java.rmi.server.useLocalHostname";
+    String DISABLEHTTP_PROP = "java.rmi.server.disableHttp";
+    String IGNORESTUBCLASSES_PROP = "java.rmi.server.ignoreStubClasses";
+
+    /*
+     * -------------------------------------------------------------------------
+     * harmony.rmi.* supported properties
+     * -------------------------------------------------------------------------
+     */
+
+    // Server properties.
+    String DGCACKTIMEOUT_PROP = "harmony.rmi.dgc.ackTimeout";
+    String DGCCHECKINTERVAL_PROP = "harmony.rmi.dgc.checkInterval";
+    String DGCLOGLEVEL_PROP = "harmony.rmi.dgc.logLevel";
+    String LOADERLOGLEVEL_PROP = "harmony.rmi.loader.logLevel";
+    String EXCEPTIONTRACE_PROP = "harmony.rmi.server.exceptionTrace";
+    String SUPPRESSSTACKTRACES_PROP = "harmony.rmi.server.suppressStackTraces";
+    String TRANSPORTLOGLEVEL_PROP = "harmony.rmi.transport.logLevel";
+    String LOCALHOSTNAMETIMEOUT_PROP = "harmony.rmi.transport.tcp.localHostNameTimeOut";
+    String TRANSPORTTCPLOGLEVEL_PROP = "harmony.rmi.transport.tcp.logLevel";
+    String READTIMEOUT_PROP = "harmony.rmi.transport.tcp.readTimeout";
+
+    // Client properties.
+    String LOGCLIENT_PROP = "harmony.rmi.client.logCalls";
+    String DGCCLEANINTERVAL_PROP = "harmony.rmi.dgc.cleanInterval";
+    String SERVERLOGLEVEL_PROP = "harmony.rmi.server.logLevel";
+    String CLIENTLOGLEVEL_PROP = "harmony.rmi.client.logLevel";
+    String CONNECTIONTIMEOUT_PROP = "harmony.rmi.transport.connectionTimeout";
+    String CONNECTTIMEOUT_PROP = "harmony.rmi.transport.proxy.connectTimeout";
+    String EAGERHTTPFALLBACK_PROP = "harmony.rmi.transport.proxy.eagerHttpFallback";
+    String TRANSPORTPROXYLOGLEVEL_PROP = "harmony.rmi.transport.proxy.logLevel";
+    String HANDSHAKETIMEOUT_PROP = "harmony.rmi.transport.tcp.handshakeTimeout";
+
+    // Activation properties.
+    String ACTIVATIONLOGLEVEL_PROP = "harmony.rmi.activation.logLevel";
+    String ACTIVATION_EXECTIMEOUT_PROP = "harmony.rmi.activation.execTimeout";
+    String MAXSTARTGROUP_PROP = "harmony.rmi.activation.groupThrottle";
+    String ACTIVATION_SNAPSHOTINTERVAL_PROP = "harmony.rmi.activation.snapshotInterval";
+    String ACTIVATION_LOG_DEBUG_PROP = "harmony.rmi.log.debug";
+    String ACTIVATION_DEBUGEXEC_PROP = "harmony.rmi.server.activation.debugExec";
+
+    /*
+     * -------------------------------------------------------------------------
+     * Additional proxy properties
+     * -------------------------------------------------------------------------
+     */
+
+    /**
+     * Name of the system property containing HTTP proxy host name.
+     */
+    String PROXY_HOST_PROP = "http.proxyHost";
+
+    /**
+     * Name of the system property containing HTTP proxy port number.
+     */
+    String PROXY_PORT_PROP = "http.proxyPort";
+
+    /**
+     * Name of the property allowing to disable direct socket connections.
+     */
+    String DISABLE_DIRECT_SOCKET_PROP =
+            "org.apache.harmony.rmi.transport.disableDirectSocket";
+
+    /**
+     * Name of the property allowing to enable direct HTTP connections.
+     */
+    String ENABLE_DIRECT_HTTP_PROP =
+            "org.apache.harmony.rmi.transport.proxy.enableDirectHTTP";
+
+    /**
+     * Name of the property allowing to disable plain HTTP connections
+     * (and force CGI instead).
+     */
+    String DISABLE_PLAIN_HTTP_PROP =
+            "org.apache.harmony.rmi.transport.proxy.disablePlainHTTP";
+
+    /*
+     * -------------------------------------------------------------------------
+     * Additional Activation properties
+     * -------------------------------------------------------------------------
+     */
+
+    /**
+     * @see org.apache.harmony.rmi.common.RMIConstants#DEFAULT_ACTIVATION_MONITOR_CLASS_NAME
+     */
+    String ACTIVATION_MONITOR_CLASS_NAME_PROP =
+            "org.apache.harmony.rmi.activation.monitor";
+
+    /*
+     * -------------------------------------------------------------------------
+     * RMI Compiler properties
+     * -------------------------------------------------------------------------
+     */
+
+    /**
+     * Property specifying the compiler class to use.
+     */
+    String JAVA_COMPILER_CLASS_PROPERTY =
+            "org.apache.harmony.rmi.compiler.class";
+
+    /**
+     * Property specifying the compiler class method to use.
+     */
+    String JAVA_COMPILER_METHOD_PROPERTY =
+            "org.apache.harmony.rmi.compiler.method";
+
+    /**
+     * Property specifying the compiler executable to use.
+     */
+    String JAVA_COMPILER_EXECUTABLE_PROPERTY =
+            "org.apache.harmony.rmi.compiler.executable";
+}

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

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMIUtil.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMIUtil.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMIUtil.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/RMIUtil.java Thu May 18 13:01:22 2006
@@ -0,0 +1,626 @@
+/*
+ * 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, Vasily Zakharov
+ * @version $Revision: 1.1.2.3 $
+ */
+package org.apache.harmony.rmi.common;
+
+import java.io.IOException;
+
+import java.lang.reflect.Method;
+
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.UnknownHostException;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Utility class for RMI implementation.
+ *
+ * This class cannot be instantiated.
+ *
+ * @author  Mikhail A. Markov, Vasily Zakharov
+ * @version $Revision: 1.1.2.3 $
+ */
+public final class RMIUtil {
+
+    /**
+     * This class cannot be instantiated.
+     */
+    private RMIUtil() {}
+
+    /**
+     * Returns wrapping Object class for specified primitive class.
+     *
+     * @param   cls
+     *          Class to wrap.
+     *
+     * @return  Wrapping Object class for <code>cls</code>, if <code>cls</code>
+     *          is Object class itself (e. g. <code>Vector</code>),
+     *          <code>cls</code> itself is returned, for primitive types
+     *          (e. g. <code>int</code>) the respective wrapping Object class
+     *          is returned (in case of <code>int</code>, {@link Integer}).
+     */
+    public static Class getWrappingClass(Class cls) {
+        if (cls == boolean.class) {
+            return Boolean.class;
+        } else if (cls == char.class) {
+            return Character.class;
+        } else if (cls == byte.class) {
+            return Byte.class;
+        } else if (cls == short.class) {
+            return Short.class;
+        } else if (cls == int.class) {
+            return Integer.class;
+        } else if (cls == long.class) {
+            return Long.class;
+        } else if (cls == float.class) {
+            return Float.class;
+        } else if (cls == double.class) {
+            return Double.class;
+        } else if (cls == void.class) {
+            return Void.class;
+        } else { // Object type.
+            return cls;
+        }
+    }
+
+    /**
+     * Returns package name for the class.
+     *
+     * @param   cls
+     *          Class to get package name for.
+     *
+     * @return  Package name of the class,
+     *          or <code>null</code> if class does not belong to a package.
+     */
+    public static String getPackageName(Class cls) {
+        if (cls.isArray() || cls.isPrimitive()) {
+            return null;
+        }
+        String name = cls.getName();
+        int index = name.lastIndexOf('.');
+
+        return ((index > 0) ? name.substring(0, index) : null);
+    }
+
+    /**
+     * Returns canonical name for the class, e. g. full class name with
+     * package name, with <code>[]</code> appended to the end for array types.
+     * Handles local classes correctly.
+     *
+     * @param   cls
+     *          Class to get canonical name for.
+     *
+     * @return  Canonical name of the class.
+     *
+     * @todo    Remove completely for Java 5.0 in favor of
+     *          <code>Class.getCanonicalName()</code>.
+     */
+    public static String getCanonicalName(Class cls) {
+        if (cls.isArray()) {
+            // Use recursion to create name for array class.
+            return (getCanonicalName(cls.getComponentType()) + "[]");
+        }
+        Class declaring = cls.getDeclaringClass();
+
+        if (declaring != null) {
+            // Use recursion to create name for local classes.
+            return (getCanonicalName(declaring) + '.' + getSimpleName(cls));
+        }
+        return cls.getName();
+    }
+
+    /**
+     * Returns short canonical name for the class, e. g. short class name
+     * without package name (but with '.' symbols for local classes),
+     * with <code>[]</code> appended to the end for array types.
+     *
+     * @param   cls
+     *          Class to get short canonical name for.
+     *
+     * @return  Short canonical name of the class.
+     */
+    public static String getShortCanonicalName(Class cls) {
+        if (cls.isArray()) {
+            // Use recursion to create name for array class.
+            return (getShortCanonicalName(cls.getComponentType()) + "[]");
+        }
+
+        // The last dot in full name separates class name from package name.
+        int index = cls.getName().lastIndexOf('.');
+
+        // Canonical name uses dots to separate local class names.
+        String name = getCanonicalName(cls);
+
+        return ((index > 0) ? name.substring(index + 1) : name);
+    }
+
+    /**
+     * Returns short name for the class, e. g. short class name without
+     * package name (but with '$' symbols for local classes),
+     * with <code>[]</code> appended to the end for array types.
+     *
+     * @param   cls
+     *          Class to get short name for.
+     *
+     * @return  Short name of the class.
+     */
+    public static String getShortName(Class cls) {
+        if (cls.isArray()) {
+            // Use recursion to create name for array class.
+            return (getShortName(cls.getComponentType()) + "[]");
+        }
+        String name = cls.getName();
+        int index = name.lastIndexOf('.');
+
+        return ((index > 0) ? name.substring(index + 1) : name);
+    }
+
+    /**
+     * Returns simple name for the class, e. g. short class name without
+     * package name or declaring class name, with <code>[]</code> appended
+     * to the end for array types.
+     *
+     * @param   cls
+     *          Class to get simple name for.
+     *
+     * @return  Simple name of the class.
+     *
+     * @todo    Remove completely for Java 5.0 in favor of
+     *          <code>Class.getSimpleName()</code>.
+     */
+    public static String getSimpleName(Class cls) {
+        if (cls.isArray()) {
+            // Use recursion to create name for array class.
+            return (getSimpleName(cls.getComponentType()) + "[]");
+        }
+        String name = cls.getName();
+        Class declaring = cls.getDeclaringClass();
+
+        if (declaring != null) {
+            // Use substringing to extract simple name of a local class.
+            return (name.substring(declaring.getName().length() + 1));
+        }
+        int index = name.lastIndexOf('.');
+
+        return ((index > 0) ? name.substring(index + 1) : name);
+    }
+
+    /**
+     * Returns system name for the class, e. g.
+     * <code>I</code> for <code>int</code>,
+     * <code>[[B</code> for <code>boolean[][]</code>,
+     * <code>[Ljava/lang/String;</code> for <code>String[]</code>.
+     *
+     * @param   cls
+     *          Class to get system name for.
+     *
+     * @return  System name of the class.
+     */
+    public static String getSystemName(Class cls) {
+        if (cls == boolean.class) {
+            return "Z";
+        } else if (cls == char.class) {
+            return "C";
+        } else if (cls == byte.class) {
+            return "B";
+        } else if (cls == short.class) {
+            return "S";
+        } else if (cls == int.class) {
+            return "I";
+        } else if (cls == long.class) {
+            return "J";
+        } else if (cls == float.class) {
+            return "F";
+        } else if (cls == double.class) {
+            return "D";
+        } else if (cls == void.class) {
+            return "V";
+        } else { // Object type.
+            String className = cls.getName().replace('.', '/');
+
+            // Add reference to non-array reference types.
+            return (cls.isArray() ? className : ('L' + className + ';'));
+        }
+    }
+
+    /**
+     * Returns method descriptor as specified in section 4.3.3
+     * of Virtual Machine Specification.
+     *
+     * @param   method
+     *          Method to return descriptor for.
+     *
+     * @return  Method descriptor.
+     */
+    public static String getMethodDescriptor(Method method) {
+        StringBuffer buffer = new StringBuffer().append('(');
+        Class[] parameters = method.getParameterTypes();
+
+        for (int i = 0; i < parameters.length; i++) {
+            buffer.append(getSystemName(parameters[i]));
+        }
+        buffer.append(')').append(getSystemName(method.getReturnType()));
+
+        return buffer.toString();
+    }
+
+    /**
+     * Returns extended method descriptor,
+     * i. e. method name appended with method descriptor
+     * as specified in section 4.3.3
+     * of Virtual Machine Specification.
+     *
+     * @param   method
+     *          Method to return extended descriptor for.
+     *
+     * @return  Extended method descriptor.
+     */
+    public static String getExtendedMethodDescriptor(Method method) {
+        return (method.getName() + getMethodDescriptor(method));
+    }
+
+    /**
+     * Returns basic method signature (method name and full parameters
+     * class names) for the method.
+     *
+     * @param   method
+     *          Method to get basic signature for.
+     *
+     * @return  Basic method signature (method name and full parameters
+     *          class names) for the method. For example, for this particular
+     *          method the long signature will be: <code>
+     *          "getBasicMethodSignature(java.lang.reflect.Method)"</code>.
+     */
+    public static String getBasicMethodSignature(Method method) {
+        // Start with method name.
+        StringBuffer buffer = new StringBuffer()
+                .append(method.getName()).append('(');
+        Class[] parameters = method.getParameterTypes();
+
+        // Append names of parameter types.
+        for (int i = 0; i < parameters.length; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            buffer.append(getCanonicalName(parameters[i]));
+        }
+        return buffer.append(')').toString();
+    }
+
+    /**
+     * Returns long method signature (return type, method name and full
+     * parameters class names) for the method.
+     *
+     * @param   method
+     *          Method to get long signature for.
+     *
+     * @return  Long method signature (return type, method name and full
+     *          parameters class names) for the method. For example, for this
+     *          particular method the long signature will be: <code>
+     *          "java.lang.String
+     *          getLongMethodSignature(java.lang.reflect.Method)"</code>.
+     */
+    public static String getLongMethodSignature(Method method) {
+        StringBuffer suffix = new StringBuffer();
+        Class cls = method.getReturnType();
+
+        // Create signature suffix for array types.
+        while (cls.isArray()) {
+            suffix.append("[]");
+            cls = cls.getComponentType();
+        }
+        return (getCanonicalName(cls) + ' '
+                + getBasicMethodSignature(method) + suffix);
+    }
+
+    /**
+     * Returns short method signature (without return type,
+     * declaring class name or parameters package names) for the method.
+     *
+     * @param   method
+     *          Method to get short signature for.
+     *
+     * @return  Short method signature (without return type,
+     *          declaring class name or parameters package names)
+     *          for the method. For example, for this particular method
+     *          the short signature will be:
+     *          <code>"getShortMethodSignature(Method)"</code>.
+     */
+    public static String getShortMethodSignature(Method method) {
+        // Start with method name.
+        StringBuffer buffer = new StringBuffer(method.getName() + '(');
+        Class[] parameters = method.getParameterTypes();
+
+        // Append short names of parameter types.
+        for (int i = 0; i < parameters.length; i++) {
+            buffer.append(((i > 0) ? ", " : "")
+                    + getShortCanonicalName(parameters[i]));
+        }
+        return buffer.append(')').toString();
+    }
+
+    /**
+     * Validates remote interface.
+     * Particularly, checks that all methods throw {@link RemoteException}.
+     *
+     * @param   iface
+     *          Interface to validate.
+     *
+     * @return  <code>true</code> if the specified class is a valid remote
+     *          interface, <code>false</code> if the specified class is not
+     *          a remote interface.
+     *
+     * @throws  IllegalArgumentException
+     *          If specified class is not an interface or if it implements
+     *          {@link java.rmi.Remote} but is not a valid remote interface.
+     */
+    public static boolean checkRemoteInterface(Class iface)
+            throws IllegalArgumentException {
+        if (!iface.isInterface()) {
+            // This is not an interface.
+            throw new IllegalArgumentException(iface.getName()
+                    + " is not an interface");
+        }
+
+        if (!Remote.class.isAssignableFrom(iface)) {
+            // This is not a remote interface.
+            return false;
+        }
+
+        // Extract all methods from the specified interface.
+        Method methods[] = iface.getMethods();
+
+        methods:
+        for (int i = 0; i < methods.length; i++) {
+            Method method = methods[i];
+
+            // Extract thrown exceptions list from a particular method.
+            Iterator j = Arrays.asList(method.getExceptionTypes()).iterator();
+
+            while (j.hasNext()) {
+                // Search for exception that extends RemoteException.
+                if (((Class) j.next()).isAssignableFrom(RemoteException.class))
+                    continue methods;
+            }
+            throw new IllegalArgumentException(iface.getName()
+                    + " is not a valid remote interface: method "
+                    + getBasicMethodSignature(method)
+                    + " must throw java.rmi.RemoteException");
+        }
+        return true;
+    }
+
+    /**
+     * Returns the list of implemented remote interfaces for the specified
+     * class.
+     *
+     * @param   cls
+     *          Class to return list of remote interfaces for.
+     *
+     * @return  Array of remote interfaces implemented by the specified class.
+     *          May be empty if the specified class is not a remote class
+     *          or if <code>cls</code> is <code>null</code>.
+     *
+     * @throws  IllegalArgumentException
+     *          If class implements any invalid remote interfaces.
+     */
+    public static Class[] getRemoteInterfaces(Class cls)
+            throws IllegalArgumentException {
+        List interfaces = new LinkedList();
+
+        for (; cls != null; cls = cls.getSuperclass()) {
+            // Get the list of interfaces the class implements.
+            Class[] interfacesArray = cls.getInterfaces();
+
+            // Walk through all interfaces the class implements.
+            for (int i = 0; i < interfacesArray.length; i++) {
+                Class iface = interfacesArray[i];
+
+                // Ignore duplicates and non-Remote interfaces.
+                if (!interfaces.contains(iface)
+                        && checkRemoteInterface(iface)) {
+                    // Add this interface to the interfaces table.
+                    interfaces.add(iface);
+                }
+            }
+        }
+        return (Class[]) interfaces.toArray(new Class[interfaces.size()]);
+    }
+
+    /**
+     * Returns the string representation of the list of remote interfaces
+     * implemented by the specified class.
+     *
+     * @param   cls
+     *          Class to find remote interfaces for.
+     *
+     * @return  List of remote interfaces for the specified class.
+     *
+     * @throws  IllegalArgumentException
+     *          If some error occured while creating the list.
+     */
+    public static String[] getRemoteInterfacesNames(Class cls)
+            throws IllegalArgumentException {
+        Class[] interfaces = getRemoteInterfaces(cls);
+
+        if ((interfaces == null) || (interfaces.length == 0)) {
+            return new String[0];
+        }
+        String[] interfStr = new String[interfaces.length];
+
+        for (int i = 0; i < interfaces.length; ++i) {
+            interfStr[i] = interfaces[i].getName();
+        }
+        return interfStr;
+    }
+
+    /**
+     * Returns a map containing all remote methods of the specified class
+     * (i. e. all methods contained in {@link Remote} interfaces implemented
+     * by the class). Hashes of methods are keys in this map.
+     *
+     * @param   cls
+     *          Class to list remote methods for.
+     *
+     * @return  Map containing all the remote methods of the specified class
+     *          and having method hashes as keys.
+     *
+     * @throws  RMIHashException
+     *          If error occured while calculating method hash.
+     */
+    public static Map getRemoteMethods(Class cls) throws RMIHashException {
+        Map map = new HashMap();
+
+        for (; cls != null; cls = cls.getSuperclass()) {
+            Class[] interf = cls.getInterfaces();
+
+            for (int i = 0; i < interf.length; ++i) {
+                if (!Remote.class.isAssignableFrom(interf[i])) {
+                    continue;
+                }
+                Method[] m = interf[i].getMethods();
+
+                for (int j = 0; j < m.length; ++j) {
+                    // Calculate the hash for the method.
+                    long hash = RMIHash.getMethodHash(m[j]);
+                    map.put(new Long(hash), m[j]);
+                }
+            }
+        }
+        return map;
+    }
+
+    /**
+     * Finds the superclass of the specified class that directly implements
+     * remote interface(s).
+     *
+     * @param   cls
+     *          Class to check for remote superclass.
+     *
+     * @return  The class found.
+     *
+     * @throws  IllegalArgumentException
+     *          If the specified class is not remote.
+     */
+    public static Class getRemoteClass(Class cls)
+            throws IllegalArgumentException {
+        for (; cls != null; cls = cls.getSuperclass()) {
+            Class[] interfaces = cls.getInterfaces();
+
+            for (int i = 0; i < interfaces.length; ++i) {
+                if (Remote.class.isAssignableFrom(interfaces[i])) {
+                    return cls;
+                }
+            }
+        }
+        throw new IllegalArgumentException("The specified class is not remote");
+    }
+
+    /**
+     * Returns <code>true</code> if the specified hostName is a local host
+     * and <code>false</code> otherwise.
+     *
+     * @param   hostName
+     *          The name of the host to check.
+     *
+     * @return  <code>true</code> if the specified hostName is a local host
+     *          and <code>false</code> otherwise.
+     *
+     * @throws  UnknownHostException
+     *          If the specified host name could not be resolved.
+     */
+    public static boolean isLocalHost(final String hostName)
+            throws UnknownHostException {
+        if (hostName == null) {
+            return true;
+        }
+
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction() {
+                public Object run() throws UnknownHostException, IOException {
+                    // Resolve the host name.
+                    InetAddress hostAddr = InetAddress.getByName(hostName);
+
+                    // Check if this address is really local.
+                    ServerSocket ss = new ServerSocket(0, 1, hostAddr);
+
+                    try {
+                        ss.close();
+                    } catch (IOException ioe) {
+                        // Ignoring.
+                    }
+                    return null;
+                }
+            });
+        } catch (PrivilegedActionException pae) {
+            Exception ex = pae.getException();
+
+            if (ex instanceof UnknownHostException) {
+                throw (UnknownHostException) ex;
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns <code>true</code> if the first specified class loader
+     * is a parent class loader (or equal) to the second specified class loader
+     * and <code>false</code> otherwise.
+     *
+     * @param   cl1
+     *          First class loader.
+     *
+     * @param   cl2
+     *          Second class loader.
+     *
+     * @return  <code>true</code> if the first class loader is a parent
+     *          (or equal) to the second class loader.
+     */
+    public static boolean isParentLoader(ClassLoader cl1, ClassLoader cl2) {
+        if (cl1 == null) {
+            // cl1 is a bootstrap or system class loader.
+            return true;
+        }
+
+        for (; cl2 != null; cl2 = cl2.getParent()) {
+            if (cl1 == cl2) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

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

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/SubProcess.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/SubProcess.java?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/SubProcess.java (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/SubProcess.java Thu May 18 13:01:22 2006
@@ -0,0 +1,830 @@
+/*
+ * 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.2 $
+ */
+package org.apache.harmony.rmi.common;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+
+/**
+ * Allows for execution of external applications as subprocesses.
+ *
+ * @author  Vasily Zakharov
+ * @version $Revision: 1.1.2.2 $
+ *
+ * @todo    Check with <code>ProcessBuilder</code> for Java 5.0.
+ */
+public final class SubProcess {
+
+    /**
+     * Default argument to {@link #tell(String)}
+     * and expect {@link #expect(String)} methods.
+     */
+    public static final String READY_STRING = "PROCESS_READY";
+
+    /**
+     * Process.
+     */
+    private Process process;
+
+    /**
+     * Data input stream.
+     */
+    private DataInputStream dataInput;
+
+    /**
+     * Data output stream.
+     */
+    private DataOutputStream dataOutput;
+
+    /**
+     * Data error stream.
+     */
+    private DataInputStream dataError;
+
+    /**
+     * Process input stream.
+     */
+    private InputStream processInput;
+
+    /**
+     * Process output stream.
+     */
+    private OutputStream processOutput;
+
+    /**
+     * Process error stream.
+     */
+    private InputStream processError;
+
+    /**
+     * Pipe target input stream.
+     */
+    private InputStream targetInput;
+
+    /**
+     * Pipe target output stream.
+     */
+    private OutputStream targetOutput;
+
+    /**
+     * Pipe target error stream.
+     */
+    private OutputStream targetError;
+
+    /**
+     * Creates subprocess with full control of its streams.
+
+     * Equivalent to
+     * {@link #SubProcess(String[], boolean, OutputStream, boolean, InputStream, boolean, OutputStream)
+     * SubProcess(args, true, System.out, true, System.in, true, System.err)}.
+     *
+     * @param   args
+     *          Program name and command line arguments
+     *          (as for {@link Runtime#exec(String[])}).
+     *
+     * @throws  IOException
+     */
+    public SubProcess(String[] args) throws IOException {
+        this(args, true, System.out, true, System.in, true, System.err);
+    }
+
+    /**
+     * Creates instance of this class with no control of its streams.
+     * If <code>pipe</code> is <code>true</code>, the streams are piped
+     * to the respective system streams of the current process.
+     * This is equivalent to
+     * {@link #SubProcess(String[], boolean, OutputStream, boolean, InputStream, boolean, OutputStream)
+     * SubProcess(args, false, System.out, false, System.in, false, System.err)}.
+     *
+     * If <code>pipe</code> is <code>false</code>, the streams are discarded.
+     * This is equivalent to
+     * {@link #SubProcess(String[], boolean, OutputStream, boolean, InputStream, boolean, OutputStream)
+     * SubProcess(args, false, null, false, null, false, null)}.
+     *
+     * @param   args
+     *          Program name and command line arguments
+     *          (as for {@link Runtime#exec(String[])}).
+     *
+     * @param   pipe
+     *          If <code>true</code>, the streams are piped
+     *          to the respective system streams of the current process,
+     *          if <code>false</code>, the streams are discarded.
+     *
+     * @throws  IOException
+     */
+    public SubProcess(String[] args, boolean pipe) throws IOException {
+        this(args, false, (pipe ? System.out : null),
+                   false, (pipe ? System.in : null),
+                   false, (pipe ? System.err : null));
+    }
+
+    /**
+     * Creates instance of this class with no control of its streams.
+     * This is equivalent to
+     * {@link #SubProcess(String[], boolean, OutputStream, boolean, InputStream, boolean, OutputStream)
+     * SubProcess(args, false, outputStream, false, inputStream, false, errorStream)}.
+     *
+     * @param   args
+     *          Program name and command line arguments
+     *          (as for {@link Runtime#exec(String[])}).
+     *
+     * @param   outputStream
+     *          Output stream to pipe program input to
+     *          if <code>inputControl</code> is <code>false</code>.
+     *          May be <code>null</code>,
+     *          in this case input from the program is discarded.
+     *
+     * @param   inputStream
+     *          Input stream to pipe to the program output stream
+     *          if <code>outputControl</code> is <code>false</code>.
+     *          May be <code>null</code>,
+     *          in this case the program output stream is closed.
+     *
+     * @param   errorStream
+     *          Error stream to pipe program error input to
+     *          if <code>errorControl</code> is <code>false</code>.
+     *          May be <code>null</code>,
+     *          in this case error input from the program is discarded.
+     *
+     * @throws  IOException
+     */
+    public SubProcess(String[] args,
+            OutputStream outputStream, InputStream inputStream,
+            OutputStream errorStream) throws IOException {
+        this(args, false, outputStream, false, inputStream, false, errorStream);
+    }
+
+    /**
+     * Creates instance of this class.
+     *
+     * @param   args
+     *          Program name and command line arguments
+     *          (as for {@link Runtime#exec(String[])}).
+     *
+     * @param   inputControl
+     *          If <code>true</code>, input from the program is available
+     *          to {@link #expect()} methods and <code>outputStream</code>
+     *          parameter is ignored, otherwise it is piped to the specified
+     *          <code>outputStream</code>.
+     *
+     * @param   outputStream
+     *          Output stream to pipe program input to
+     *          if <code>inputControl</code> is <code>false</code>.
+     *          May be <code>null</code>,
+     *          in this case input from the program is discarded.
+     *
+     * @param   outputControl
+     *          If <code>true</code>, output stream to the program is available
+     *          to {@link #tell()} methods and <code>inputStream</code>
+     *          parameter is ignored, otherwise the specified
+     *          <code>inputStream</code> is piped to program output stream.
+     *
+     * @param   inputStream
+     *          Input stream to pipe to the program output stream
+     *          if <code>outputControl</code> is <code>false</code>.
+     *          May be <code>null</code>,
+     *          in this case the program output stream is closed.
+     *
+     * @param   errorControl
+     *          If <code>true</code>, error input from the program is available
+     *          to {@link #expectError()} methods and <code>errorStream</code>
+     *          parameter is ignored, otherwise it is piped to the specified
+     *          <code>errorStream</code>.
+     *
+     * @param   errorStream
+     *          Error stream to pipe program error input to
+     *          if <code>errorControl</code> is <code>false</code>.
+     *          May be <code>null</code>,
+     *          in this case error input from the program is discarded.
+     *
+     * @throws  IOException
+     */
+    public SubProcess(String[] args,
+            boolean inputControl, OutputStream outputStream,
+            boolean outputControl, InputStream inputStream,
+            boolean errorControl, OutputStream errorStream) throws IOException {
+        process = Runtime.getRuntime().exec(args);
+
+        processInput = process.getInputStream();
+        processOutput = process.getOutputStream();
+        processError = process.getErrorStream();
+
+        targetInput = inputStream;
+        targetOutput = outputStream;
+        targetError = errorStream;
+
+        if (inputControl) {
+            dataInput = new DataInputStream(processInput);
+        } else {
+            dataInput = null;
+            doPipeInput();
+        }
+
+        if (outputControl) {
+            dataOutput = new DataOutputStream(processOutput);
+        } else {
+            dataOutput = null;
+            doPipeOutput();
+        }
+
+        if (errorControl) {
+            dataError = new DataInputStream(processError);
+        } else {
+            dataError = null;
+            doPipeError();
+        }
+    }
+
+    /**
+     * Discards the remaining input.
+     * Usable when <code>inputControl</code> is enabled
+     * but there's nothing else to {@linkplain #expect() expect}.
+     */
+    public void discardInput() {
+        pipeInput(null);
+    }
+
+    /**
+     * Pipes the remaining input to the target output stream
+     * specified in <a href="#constructor_detail">constructor</a>.
+     * Usable when <code>inputControl</code> is enabled
+     * but there's nothing else to {@linkplain #expect() expect}.
+     */
+    public void pipeInput() {
+        pipeInput(targetOutput);
+    }
+
+    /**
+     * Pipes the remaining input to the specified output stream.
+     * Usable when <code>inputControl</code> is enabled
+     * but there's nothing else to {@linkplain #expect() expect}.
+     *
+     * @param   outputStream
+     *          Output stream to pipe program input to.
+     *          May be <code>null</code>,
+     *          in this case input from the program is discarded.
+     */
+    public void pipeInput(OutputStream outputStream) {
+        if (dataInput != null) {
+            dataInput = null;
+            targetOutput = outputStream;
+            doPipeInput();
+        }
+    }
+
+    /**
+     * Creates pipe from process input to target output.
+     */
+    private void doPipeInput() {
+        new StreamPipe(processInput, targetOutput).start();
+    }
+
+    /**
+     * Closes the program output.
+     * Usable when <code>outputControl</code> is enabled
+     * but there's nothing else to {@linkplain #tell() tell}.
+     */
+    public void closeOutput() {
+        pipeOutput(null);
+    }
+
+    /**
+     * Pipes the target input stream specified in
+     * <a href="#constructor_detail">constructor</a>
+     * to the program output stream.
+     * Usable when <code>outputControl</code> is enabled
+     * but there's nothing else to {@linkplain #tell() tell}.
+     */
+    public void pipeOutput() {
+        pipeOutput(targetInput);
+    }
+
+    /**
+     * Pipes the specified input stream to the program output stream.
+     * Usable when <code>outputControl</code> is enabled
+     * but there's nothing else to {@linkplain #tell() tell}.
+     *
+     * @param   inputStream
+     *          Input stream to pipe to the program output.
+     *          May be <code>null</code>,
+     *          in this case the program output stream is closed.
+     */
+    public void pipeOutput(InputStream inputStream) {
+        if (dataOutput != null) {
+            dataOutput = null;
+            targetInput = inputStream;
+            doPipeOutput();
+        }
+    }
+
+    /**
+     * Creates pipe from target input to process output
+     * or closes process output if target input is <code>null</code>.
+     */
+    private void doPipeOutput() {
+        if (targetInput != null) {
+            new StreamPipe(targetInput, processOutput).start();
+        } else {
+            try {
+                processOutput.close();
+            } catch (IOException e) {}
+        }
+    }
+
+    /**
+     * Discards the remaining error input.
+     * Usable when <code>errorControl</code> is enabled
+     * but there's nothing else to {@linkplain #expectError() expect}.
+     */
+    public void discardError() {
+        pipeError(null);
+    }
+
+    /**
+     * Pipes the remaining error input to the target error stream
+     * specified in <a href="#constructor_detail">constructor</a>.
+     * Usable when <code>errorControl</code> is enabled
+     * but there's nothing else to {@linkplain #expectError() expect}.
+     */
+    public void pipeError() {
+        pipeError(targetError);
+    }
+
+    /**
+     * Pipes the remaining error input to the specified error stream.
+     * Usable when <code>errorControl</code> is enabled
+     * but there's nothing else to {@linkplain #expectError() expect}.
+     *
+     * @param   errorStream
+     *          Error stream to pipe program error input to.
+     *          May be <code>null</code>,
+     *          in this case error input from the program is discarded.
+     */
+    public void pipeError(OutputStream errorStream) {
+        if (dataError != null) {
+            dataError = null;
+            targetError = errorStream;
+            doPipeError();
+        }
+    }
+
+    /**
+     * Creates pipe from process error input to target error output.
+     */
+    private void doPipeError() {
+        new StreamPipe(processError, targetError).start();
+    }
+
+    /**
+     * Waits for subprocess to terminate and returns its exit code.
+     *
+     * @return  The subprocess exit code.
+     */
+    public int waitFor() {
+        while (true) {
+            try {
+                return process.waitFor();
+            } catch (InterruptedException e) {}
+        }
+    }
+
+    /**
+     * Destroys this subprocess.
+     */
+    public void destroy() {
+        process.destroy();
+        dataInput = null;
+        dataOutput = null;
+        dataError = null;
+    }
+
+    /**
+     * Writes the {@linkplain #READY_STRING default "ready" string}
+     * to the process output stream.
+     *
+     * @throws  IllegalStateException
+     *          If subprocess output stream control is disabled.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public void tell() throws IllegalStateException, IOException {
+        tell(READY_STRING);
+    }
+
+    /**
+     * Writes the specified string to the process output stream.
+     *
+     * @param   str
+     *          String to write.
+     *
+     * @throws  IllegalStateException
+     *          If subprocess output stream control is disabled.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public void tell(String str) throws IllegalStateException, IOException {
+        if (dataOutput == null) {
+            throw new IllegalStateException(
+                    "Subprocess output stream control disabled");
+        }
+        tell(dataOutput, str);
+    }
+
+    /**
+     * Writes the {@linkplain #READY_STRING default "ready" string}
+     * to the {@linkplain System#out system output stream}.
+     *
+     * This static method is usable by child subprocesses
+     * for communication with the parent process.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public static void tellOut() throws IOException {
+        tellOut(READY_STRING);
+    }
+
+    /**
+     * Writes the specified string to the
+     * {@linkplain System#out system output stream}.
+     *
+     * This static method is usable by child subprocesses
+     * for communication with the parent process.
+     *
+     * @param   str
+     *          String to write.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public static void tellOut(String str) throws IOException {
+        tell(new DataOutputStream(System.out), str);
+    }
+
+    /**
+     * Writes the {@linkplain #READY_STRING default "ready" string}
+     * to the {@linkplain System#err system error stream}.
+     *
+     * This static method is usable by child subprocesses
+     * for communication with the parent process.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public static void tellError() throws IOException {
+        tellError(READY_STRING);
+    }
+
+    /**
+     * Writes the specified string to the
+     * {@linkplain System#err system error stream}.
+     *
+     * This static method is usable by child subprocesses
+     * for communication with the parent process.
+     *
+     * @param   str
+     *          String to write.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public static void tellError(String str) throws IOException {
+        tell(new DataOutputStream(System.err), str);
+    }
+
+    /**
+     * Writes the specified string to the process output stream.
+     *
+     * @param   stream
+     *          Stream to write the string to.
+     *
+     * @param   str
+     *          String to write.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    private static void tell(DataOutputStream stream, String str)
+            throws IOException {
+        stream.writeBytes('\n' + str + '\n');
+        stream.flush();
+    }
+
+    /**
+     * Waits until the {@linkplain #READY_STRING default "ready" string}
+     * appears in the program input. Equivalent to
+     * {@link #expect(String, boolean, boolean) expect(READY_STRING, false, false)}.
+     *
+     * @throws  IllegalStateException
+     *          If subprocess input stream control is disabled.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public void expect() throws IllegalStateException, IOException {
+        expect(READY_STRING);
+    }
+
+    /**
+     * Waits until the specified string appears in the program input.
+     * Equivalent to
+     * {@link #expect(String, boolean, boolean) expect(str, false, false)}.
+     *
+     * @param   str
+     *          String to wait for.
+     *
+     * @throws  IllegalStateException
+     *          If subprocess input stream control is disabled.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public void expect(String str) throws IllegalStateException, IOException {
+        expect(str, false, false);
+    }
+
+    /**
+     * Waits until the specified string appears in the program input.
+     *
+     * @param   str
+     *          String to wait for.
+     *
+     * @param   whole
+     *          If <code>true</code>, the whole input lines are compared
+     *          to the specified string, otherwise the string is considered
+     *          to be found if it appears as a substring in any input line.
+     *
+     * @param   ignoreCase
+     *          If <code>true</code>, case-insensitive comparison is performed.
+     *
+     * @throws  IllegalStateException
+     *          If subprocess input stream control is disabled.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public void expect(String str, boolean whole, boolean ignoreCase)
+            throws IllegalStateException, IOException {
+        if (dataInput == null) {
+            throw new IllegalStateException(
+                    "Subprocess input stream control disabled");
+        }
+        expect(dataInput, str, whole, ignoreCase);
+    }
+
+    /**
+     * Waits until the {@linkplain #READY_STRING default "ready" string}
+     * appears in the program error input. Equivalent to
+     * {@link #expectError(String, boolean, boolean) expectError(READY_STRING, false, false)}.
+     *
+     * @throws  IllegalStateException
+     *          If subprocess error stream control is disabled.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public void expectError() throws IllegalStateException, IOException {
+        expectError(READY_STRING);
+    }
+
+    /**
+     * Waits until the specified string appears in the program error input.
+     * Equivalent to
+     * {@link #expectError(String, boolean, boolean) expectError(str, false, false)}.
+     *
+     * @param   str
+     *          String to wait for.
+     *
+     * @throws  IllegalStateException
+     *          If subprocess error stream control is disabled.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public void expectError(String str)
+            throws IllegalStateException, IOException {
+        expectError(str, false, false);
+    }
+
+    /**
+     * Waits until the specified string appears in the program error input.
+     *
+     * @param   str
+     *          String to wait for.
+     *
+     * @param   whole
+     *          If <code>true</code>, the whole input lines are compared
+     *          to the specified string, otherwise the string is considered
+     *          to be found if it appears as a substring in any input line.
+     *
+     * @param   ignoreCase
+     *          If <code>true</code>, case-insensitive comparison is performed.
+     *
+     * @throws  IllegalStateException
+     *          If subprocess error stream control is disabled.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public void expectError(String str, boolean whole, boolean ignoreCase)
+            throws IllegalStateException, IOException {
+        if (dataError == null) {
+            throw new IllegalStateException(
+                    "Subprocess error stream control disabled");
+        }
+        expect(dataError, str, whole, ignoreCase);
+    }
+
+    /**
+     * Waits until the {@linkplain #READY_STRING default "ready" string}
+     * appears in {@linkplain System#in system input stream}. Equivalent to
+     * {@link #expectIn(String, boolean, boolean) expectIn(READY_STRING, false, false)}.
+     *
+     * This static method is usable by child subprocesses
+     * for communication with the parent process.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public static void expectIn() throws IOException {
+        expectIn(READY_STRING);
+    }
+
+    /**
+     * Waits until the specified string appears in
+     * {@linkplain System#in system input stream}.
+     * Equivalent to {@link #expectIn(String, boolean, boolean) expectIn(str, false, false)}.
+     *
+     * This static method is usable by child subprocesses
+     * for communication with the parent process.
+     *
+     * @param   str
+     *          String to wait for.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public static void expectIn(String str) throws IOException {
+        expectIn(str, false, false);
+    }
+
+    /**
+     * Waits until the specified string appears in
+     * {@linkplain System#in system input stream}.
+     *
+     * This static method is usable by child subprocesses
+     * for communication with the parent process.
+     *
+     * @param   str
+     *          String to wait for.
+     *
+     * @param   whole
+     *          If <code>true</code>, the whole input lines are compared
+     *          to the specified string, otherwise the string is considered
+     *          to be found if it appears as a substring in any input line.
+     *
+     * @param   ignoreCase
+     *          If <code>true</code>, case-insensitive comparison is performed.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    public static void expectIn(String str, boolean whole, boolean ignoreCase)
+            throws IOException {
+        expect(new DataInputStream(System.in), str, whole, ignoreCase);
+    }
+
+    /**
+     * Waits until the specified string appears in the specified stream.
+     *
+     * @param   stream
+     *          Stream to wait for the string in.
+     *
+     * @param   str
+     *          String to wait for.
+     *
+     * @param   whole
+     *          If <code>true</code>, the whole input lines are compared
+     *          to the specified string, otherwise the string is considered
+     *          to be found if it appears as a substring in any input line.
+     *
+     * @param   ignoreCase
+     *          If <code>true</code>, case-insensitive comparison is performed.
+     *
+     * @throws  IOException
+     *          If I/O error occurs.
+     */
+    private static void expect(DataInputStream stream, String str,
+            boolean whole, boolean ignoreCase) throws IOException {
+        if (ignoreCase && !whole) {
+            str = str.toLowerCase();
+        }
+
+        while (true) {
+            String line = stream.readLine();
+
+            if (line == null) {
+                // End of stream
+                throw new EOFException();
+            }
+
+            if (whole ? (ignoreCase ? line.equalsIgnoreCase(str)
+                                    : line.equals(str))
+                      : ((ignoreCase ? line.toLowerCase()
+                                     : line).indexOf(str) >= 0)) {
+                // expectString is found
+                return;
+            }
+        }
+    }
+
+    /**
+     * Automatically transfers data from input to output stream
+     * using new thread.
+     *
+     * Use {@link #start()} method to start the transferring thread.
+     * The thread terminates itself when end of input stream is encountered.
+     */
+    private final class StreamPipe extends Thread {
+
+        /**
+         * Input stream.
+         */
+        private InputStream input;
+
+        /**
+         * Output stream.
+         */
+        private OutputStream output;
+
+        /**
+         * Constructs this object.
+         *
+         * @param   input
+         *          Input stream to read data from.
+         *
+         * @param   output
+         *          Output stream to write data to.
+         *          Can be <code>null</code>, in this case data are just read
+         *          from <code>input</code> stream and discarded.
+         */
+        StreamPipe(InputStream input, OutputStream output) {
+            this.input = input;
+            this.output = output;
+            setDaemon(true);
+        }
+
+        /**
+         * Runs this thread, called by VM.
+         */
+        public void run() {
+            try {
+                byte[] buffer = new byte[1024];
+                int len;
+
+                /*
+                 * Checking the streams' state seems to be unnecessary,
+                 * as soon as the thread is a daemon thread,
+                 * and will also exit at first error in either stream.
+                 */
+                while ((len = input.read(buffer)) > 0) {
+                    if (output != null) {
+                        output.write(buffer, 0, len);
+                        output.flush();
+                    }
+                }
+                assert (len == -1)
+                        : ("read(byte[]) returned unexpected value: " + len);
+            } catch (IOException e) {
+                System.err.print("StreamPipe error: ");
+                e.printStackTrace();
+            }
+        }
+    }
+}

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

Added: incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/package.html
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/package.html?rev=407625&view=auto
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/package.html (added)
+++ incubator/harmony/enhanced/classlib/trunk/modules/rmi3/src/common/javasrc/org/apache/harmony/rmi/common/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>
+RMI common implementation classes.
+</body>
+</html>

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