harmony-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ndbe...@apache.org
Subject svn commit: r446491 [6/24] - in /incubator/harmony/enhanced/classlib/trunk/modules: luni-kernel/.settings/ luni-kernel/META-INF/ luni-kernel/make/ luni-kernel/src/main/java/java/lang/ luni-kernel/src/main/java/java/lang/ref/ luni-kernel/src/main/java/j...
Date Fri, 15 Sep 2006 03:08:13 GMT
Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java?view=diff&rev=446491&r1=446490&r2=446491
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java Thu Sep 14 20:08:07 2006
@@ -1,850 +1,850 @@
-/* Copyright 1998, 2005 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.
- */
-
-package java.lang;
-
-/**
- * An implementation of this class is provided, but the documented constructors
- * are used by the vm specific implementation to create the required "system"
- * and "main" ThreadGroups. The documented methods are used by java.lang.Thread
- * to add and remove Threads from their ThreadGroups.
- * 
- * ThreadGroups are containers of Threads and ThreadGroups, therefore providing
- * a tree-like structure to organize Threads. The root ThreadGroup name is
- * "system" and it has no parent ThreadGroup. All other ThreadGroups have
- * exactly one parent ThreadGroup. All Threads belong to exactly one
- * ThreadGroup.
- * 
- * @see Thread
- * @see SecurityManager
- */
-public class ThreadGroup implements Thread.UncaughtExceptionHandler {
-
-    // Name of this ThreadGroup
-    private String name;
-
-    // Maximum priority for Threads inside this ThreadGroup
-    private int maxPriority = Thread.MAX_PRIORITY;
-
-    // The ThreadGroup to which this ThreadGroup belongs
-    ThreadGroup parent;
-
-    int numThreads;
-
-    // The Threads this ThreadGroup contains
-    private Thread[] childrenThreads = new Thread[5];
-
-    // The number of children groups
-    int numGroups;
-
-    // The ThreadGroups this ThreadGroup contains
-    private ThreadGroup[] childrenGroups = new ThreadGroup[3];
-
-    // Locked when using the childrenGroups field
-    private Object childrenGroupsLock = new Object();
-
-    // Locked when using the childrenThreads field
-    private Object childrenThreadsLock = new Object();
-
-    // Whether this ThreadGroup is a daemon ThreadGroup or not
-    private boolean isDaemon;
-
-    // Whether this ThreadGroup has already been destroyed or not
-    private boolean isDestroyed;
-
-    /**
-     * Used by the JVM to create the "system" ThreadGroup. Construct a
-     * ThreadGroup instance, and assign the name "system".
-     */
-    private ThreadGroup() {
-        name = "system";
-    }
-
-    /**
-     * Constructs a new ThreadGroup with the name provided. The new ThreadGroup
-     * will be child of the ThreadGroup to which the
-     * <code>Thread.currentThread()</code> belongs.
-     * 
-     * @param name Name for the ThreadGroup being created
-     * 
-     * @throws SecurityException if <code>checkAccess()</code> for the parent
-     *         group fails with a SecurityException
-     * 
-     * @see java.lang.Thread#currentThread
-     */
-
-    public ThreadGroup(String name) {
-        this(Thread.currentThread().getThreadGroup(), name);
-    }
-
-    /**
-     * Constructs a new ThreadGroup with the name provided, as child of the
-     * ThreadGroup <code>parent</code>
-     * 
-     * @param parent Parent ThreadGroup
-     * @param name Name for the ThreadGroup being created
-     * 
-     * @throws NullPointerException if <code>parent</code> is
-     *         <code>null</code>
-     * @throws SecurityException if <code>checkAccess()</code> for the parent
-     *         group fails with a SecurityException
-     * @throws IllegalThreadStateException if <code>parent</code> has been
-     *         destroyed already
-     */
-    public ThreadGroup(ThreadGroup parent, String name) {
-        super();
-        if (Thread.currentThread() != null) {
-            // If parent is null we must throw NullPointerException, but that
-            // will be done "for free" with the message send below
-            parent.checkAccess();
-        }
-
-        this.name = name;
-        this.setParent(parent);
-        if (parent != null) {
-            this.setMaxPriority(parent.getMaxPriority());
-            if (parent.isDaemon()) {
-                this.setDaemon(true);
-            }
-        }
-    }
-
-    /**
-     * Initialize the "main" ThreadGroup
-     */
-    ThreadGroup(ThreadGroup parent) {
-        this.name = "main";
-        this.setParent(parent);
-    }
-
-    /**
-     * Returns the number of Threads which are children of the receiver,
-     * directly or indirectly.
-     * 
-     * @return Number of children Threads
-     */
-
-    public int activeCount() {
-        int count = numThreads;
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenGroupsLock) {
-            for (int i = 0; i < numGroups; i++) {
-                count += this.childrenGroups[i].activeCount();
-            }
-        }
-        return count;
-    }
-
-    /**
-     * Returns the number of ThreadGroups which are children of the receiver,
-     * directly or indirectly.
-     * 
-     * @return Number of children ThreadGroups
-     */
-    public int activeGroupCount() {
-        int count = 0;
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenGroupsLock) {
-            for (int i = 0; i < numGroups; i++) {
-                // One for this group & the subgroups
-                count += 1 + this.childrenGroups[i].activeGroupCount();
-            }
-        }
-        return count;
-    }
-
-    /**
-     * Adds a Thread to the receiver. This should only be visible to class
-     * java.lang.Thread, and should only be called when a new Thread is created
-     * and initialized by the constructor.
-     * 
-     * @param thread Thread to add to the receiver
-     * 
-     * @throws IllegalThreadStateException if the receiver has been destroyed
-     *         already
-     * 
-     * @see #remove(java.lang.Thread)
-     */
-    final void add(Thread thread) throws IllegalThreadStateException {
-        synchronized (this.childrenThreadsLock) {
-            if (!isDestroyed) {
-                if (childrenThreads.length == numThreads) {
-                    Thread[] newThreads = new Thread[childrenThreads.length * 2];
-                    System.arraycopy(childrenThreads, 0, newThreads, 0, numThreads);
-                    newThreads[numThreads++] = thread;
-                    childrenThreads = newThreads;
-                } else {
-                    childrenThreads[numThreads++] = thread;
-                }
-            } else {
-                throw new IllegalThreadStateException();
-            }
-        }
-    }
-
-    /**
-     * Adds a ThreadGroup to the receiver.
-     * 
-     * @param g ThreadGroup to add to the receiver
-     * 
-     * @throws IllegalThreadStateException if the receiver has been destroyed
-     *         already
-     */
-    private void add(ThreadGroup g) throws IllegalThreadStateException {
-        synchronized (this.childrenGroupsLock) {
-            if (!isDestroyed) {
-                if (childrenGroups.length == numGroups) {
-                    ThreadGroup[] newGroups = new ThreadGroup[childrenGroups.length * 2];
-                    System.arraycopy(childrenGroups, 0, newGroups, 0, numGroups);
-                    newGroups[numGroups++] = g;
-                    childrenGroups = newGroups;
-                } else {
-                    childrenGroups[numGroups++] = g;
-                }
-            } else {
-                throw new IllegalThreadStateException();
-            }
-        }
-    }
-
-    /**
-     * The definition of this method depends on the deprecated method
-     * <code>suspend()</code>. The behavior of this call was never specified.
-     * 
-     * @param b Used to control low memory implicit suspension
-     * 
-     * @deprecated Required deprecated method suspend().
-     */
-    @Deprecated
-    public boolean allowThreadSuspension(boolean b) {
-        // Does not apply to this VM, no-op
-        return true;
-    }
-
-    /**
-     * If there is a SecurityManager installed, call <code>checkAccess</code>
-     * in it passing the receiver as parameter, otherwise do nothing.
-     */
-    public final void checkAccess() {
-        // Forwards the message to the SecurityManager (if there's one) passing
-        // the receiver as parameter
-        SecurityManager currentManager = System.getSecurityManager();
-        if (currentManager != null) {
-            currentManager.checkAccess(this);
-        }
-    }
-
-    /**
-     * Destroys the receiver and recursively all its subgroups. It is only legal
-     * to destroy a ThreadGroup that has no Threads. Any daemon ThreadGroup is
-     * destroyed automatically when it becomes empty (no Threads and no
-     * ThreadGroups in it).
-     * 
-     * @throws IllegalThreadStateException if the receiver or any of its
-     *         subgroups has been destroyed already
-     * @throws SecurityException if <code>this.checkAccess()</code> fails with
-     *         a SecurityException
-     */
-
-    public final void destroy() {
-        checkAccess();
-
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenThreadsLock) {
-            synchronized (this.childrenGroupsLock) {
-                int toDestroy = numGroups;
-                // Call recursively for subgroups
-                for (int i = 0; i < toDestroy; i++) {
-                    // We always get the first element - remember, when the
-                    // child dies it removes itself from our collection. See
-                    // below.
-                    this.childrenGroups[0].destroy();
-                }
-
-                if (parent != null) {
-                    parent.remove(this);
-                }
-
-                // Now that the ThreadGroup is really destroyed it can be tagged
-                // as so
-                this.isDestroyed = true;
-            }
-        }
-    }
-
-    /*
-     * Auxiliary method that destroys the receiver and recursively all its
-     * subgroups if the receiver is a daemon ThreadGroup.
-     * 
-     * @see #destroy
-     * @see #setDaemon
-     * @see #isDaemon
-     */
-    private void destroyIfEmptyDaemon() {
-        // Has to be non-destroyed daemon to make sense
-        synchronized (this.childrenThreadsLock) {
-            if (isDaemon && !isDestroyed && numThreads == 0) {
-                synchronized (this.childrenGroupsLock) {
-                    if (numGroups == 0) {
-                        destroy();
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Copies an array with all Threads which are children of the receiver
-     * (directly or indirectly) into the array <code>threads</code> passed as
-     * parameters. If the array passed as parameter is too small no exception is
-     * thrown - the extra elements are simply not copied.
-     * 
-     * @param threads Thread array into which the Threads will be copied
-     * @return How many Threads were copied over
-     * 
-     */
-    public int enumerate(Thread[] threads) {
-        return enumerate(threads, true);
-    }
-
-    /**
-     * Copies an array with all Threads which are children of the receiver into
-     * the array <code>threads</code> passed as parameter. Children Threads of
-     * subgroups are recursively copied as well if parameter
-     * <code>recurse</code> is <code>true</code>.
-     * 
-     * If the array passed as parameter is too small no exception is thrown -
-     * the extra elements are simply not copied.
-     * 
-     * @param threads array into which the Threads will be copied
-     * @param recurse Indicates whether Threads in subgroups should be
-     *        recursively copied as well or not
-     * @return How many Threads were copied over
-     * 
-     */
-    public int enumerate(Thread[] threads, boolean recurse) {
-        return enumerateGeneric(threads, recurse, 0, true);
-    }
-
-    /**
-     * Copies an array with all ThreadGroups which are children of the receiver
-     * (directly or indirectly) into the array <code>groups</code> passed as
-     * parameters. If the array passed as parameter is too small no exception is
-     * thrown - the extra elements are simply not copied.
-     * 
-     * @param groups array into which the ThreadGroups will be copied
-     * @return How many ThreadGroups were copied over
-     * 
-     */
-    public int enumerate(ThreadGroup[] groups) {
-        return enumerate(groups, true);
-    }
-
-    /**
-     * Copies an array with all ThreadGroups which are children of the receiver
-     * into the array <code>groups</code> passed as parameter. Children
-     * ThreadGroups of subgroups are recursively copied as well if parameter
-     * <code>recurse</code> is <code>true</code>.
-     * 
-     * If the array passed as parameter is too small no exception is thrown -
-     * the extra elements are simply not copied.
-     * 
-     * @param groups array into which the ThreadGroups will be copied
-     * @param recurse Indicates whether ThreadGroups in subgroups should be
-     *        recursively copied as well or not
-     * @return How many ThreadGroups were copied over
-     * 
-     */
-    public int enumerate(ThreadGroup[] groups, boolean recurse) {
-        return enumerateGeneric(groups, recurse, 0, false);
-    }
-
-    /**
-     * Copies into <param>enumeration</param> starting at
-     * <param>enumerationIndex</param> all Threads or ThreadGroups in the
-     * receiver. If <param>recurse</param> is true, recursively enumerate the
-     * elements in subgroups.
-     * 
-     * If the array passed as parameter is too small no exception is thrown -
-     * the extra elements are simply not copied.
-     * 
-     * @param enumeration array into which the elements will be copied
-     * @param recurse Indicates whether subgroups should be enumerated or not
-     * @param enumerationIndex Indicates in which position of the enumeration
-     *        array we are
-     * @param enumeratingThreads Indicates whether we are enumerating Threads or
-     *        ThreadGroups
-     * @return How many elements were enumerated/copied over
-     */
-    private int enumerateGeneric(Object[] enumeration, boolean recurse, int enumerationIndex,
-            boolean enumeratingThreads) {
-        checkAccess();
-
-        Object[] immediateCollection = enumeratingThreads ? (Object[]) childrenThreads
-                : (Object[]) childrenGroups;
-        Object syncLock = enumeratingThreads ? childrenThreadsLock : childrenGroupsLock;
-
-        synchronized (syncLock) { // Lock this subpart of the tree as we walk
-            for (int i = enumeratingThreads ? numThreads : numGroups; --i >= 0;) {
-                if (!enumeratingThreads || ((Thread) immediateCollection[i]).isAlive()) {
-                    if (enumerationIndex >= enumeration.length) {
-                        return enumerationIndex;
-                    }
-                    enumeration[enumerationIndex++] = immediateCollection[i];
-                }
-            }
-        }
-
-        if (recurse) { // Lock this subpart of the tree as we walk
-            synchronized (this.childrenGroupsLock) {
-                for (int i = 0; i < numGroups; i++) {
-                    if (enumerationIndex >= enumeration.length) {
-                        return enumerationIndex;
-                    }
-                    enumerationIndex = childrenGroups[i].enumerateGeneric(enumeration, recurse,
-                            enumerationIndex, enumeratingThreads);
-                }
-            }
-        }
-        return enumerationIndex;
-    }
-
-    /**
-     * Answers the maximum allowed priority for a Thread in the receiver.
-     * 
-     * @return the maximum priority (an <code>int</code>)
-     * 
-     * @see #setMaxPriority
-     */
-    public final int getMaxPriority() {
-        return maxPriority;
-    }
-
-    /**
-     * Answers the name of the receiver.
-     * 
-     * @return the receiver's name (a java.lang.String)
-     */
-    public final String getName() {
-        return name;
-    }
-
-    /**
-     * Answers the receiver's parent ThreadGroup. It can be null if the receiver
-     * is the the root ThreadGroup.
-     * 
-     * @return the parent ThreadGroup
-     * 
-     */
-    public final ThreadGroup getParent() {
-        if (parent != null) {
-            parent.checkAccess();
-        }
-        return parent;
-    }
-
-    /**
-     * Interrupts every Thread in the receiver and recursively in all its
-     * subgroups.
-     * 
-     * @throws SecurityException if <code>this.checkAccess()</code> fails with
-     *         a SecurityException
-     * 
-     * @see Thread#interrupt
-     */
-    public final void interrupt() {
-        checkAccess();
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenThreadsLock) {
-            for (int i = 0; i < numThreads; i++) {
-                this.childrenThreads[i].interrupt();
-            }
-        }
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenGroupsLock) {
-            for (int i = 0; i < numGroups; i++) {
-                this.childrenGroups[i].interrupt();
-            }
-        }
-    }
-
-    /**
-     * Answers true if the receiver is a daemon ThreadGroup, false otherwise.
-     * 
-     * @return if the receiver is a daemon ThreadGroup
-     * 
-     * @see #setDaemon
-     * @see #destroy
-     */
-    public final boolean isDaemon() {
-        return isDaemon;
-    }
-
-    /**
-     * Answers true if the receiver has been destroyed already, false otherwise.
-     * 
-     * @return if the receiver has been destroyed already
-     * 
-     * @see #destroy
-     */
-    public boolean isDestroyed() {
-        return isDestroyed;
-    }
-
-    /**
-     * Outputs to <code>System.out</code> a text representation of the
-     * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
-     * Proper identation is done to suggest the nesting of groups inside groups
-     * and threads inside groups.
-     */
-    public void list() {
-        // We start in a fresh line
-        System.out.println();
-        list(0);
-    }
-
-    /*
-     * Outputs to <code>System.out</code>a text representation of the
-     * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
-     * The identation will be four spaces per level of nesting.
-     * 
-     * @param levels How many levels of nesting, so that proper identetion can
-     * be output.
-     */
-    private void list(int levels) {
-        for (int i = 0; i < levels; i++) {
-            System.out.print("    "); // 4 spaces for each level
-        }
-
-        // Print the receiver
-        System.out.println(this.toString());
-
-        // Print the children threads, with 1 extra identation
-        synchronized (this.childrenThreadsLock) {
-            for (int i = 0; i < numThreads; i++) {
-                // children get an extra identation, 4 spaces for each level
-                for (int j = 0; j <= levels; j++) {
-                    System.out.print("    ");
-                }
-                System.out.println(this.childrenThreads[i]);
-            }
-        }
-        synchronized (this.childrenGroupsLock) {
-            for (int i = 0; i < numGroups; i++) {
-                this.childrenGroups[i].list(levels + 1);
-            }
-        }
-    }
-
-    /**
-     * Answers true if the receiver is a direct or indirect parent group of
-     * ThreadGroup <code>g</code>, false otherwise.
-     * 
-     * @param g ThreadGroup to test
-     * 
-     * @return if the receiver is parent of the ThreadGroup passed as parameter
-     * 
-     */
-    public final boolean parentOf(ThreadGroup g) {
-        while (g != null) {
-            if (this == g) {
-                return true;
-            }
-            g = g.parent;
-        }
-        return false;
-    }
-
-    /**
-     * Removes a Thread from the receiver. This should only be visible to class
-     * java.lang.Thread, and should only be called when a Thread dies.
-     * 
-     * @param thread Thread to remove from the receiver
-     * 
-     * @see #add(Thread)
-     */
-    final void remove(java.lang.Thread thread) {
-        synchronized (this.childrenThreadsLock) {
-            for (int i = 0; i < numThreads; i++) {
-                if (childrenThreads[i].equals(thread)) {
-                    numThreads--;
-                    System
-                            .arraycopy(childrenThreads, i + 1, childrenThreads, i, numThreads
-                                    - i);
-                    childrenThreads[numThreads] = null;
-                    break;
-                }
-            }
-        }
-        destroyIfEmptyDaemon();
-    }
-
-    /**
-     * Removes an immediate subgroup from the receiver.
-     * 
-     * @param g Threadgroup to remove from the receiver
-     * 
-     * @see #add(Thread)
-     * @see #add(ThreadGroup)
-     */
-    private void remove(ThreadGroup g) {
-        synchronized (this.childrenGroupsLock) {
-            for (int i = 0; i < numGroups; i++) {
-                if (childrenGroups[i].equals(g)) {
-                    numGroups--;
-                    System.arraycopy(childrenGroups, i + 1, childrenGroups, i, numGroups - i);
-                    childrenGroups[numGroups] = null;
-                    break;
-                }
-            }
-        }
-        destroyIfEmptyDaemon();
-    }
-
-    /**
-     * Resumes every Thread in the receiver and recursively in all its
-     * subgroups.
-     * 
-     * @throws SecurityException if <code>this.checkAccess()</code> fails with
-     *         a SecurityException
-     * 
-     * @see Thread#resume
-     * @see #suspend
-     * 
-     * @deprecated Requires deprecated method Thread.resume().
-     */
-    @SuppressWarnings("deprecation")
-    @Deprecated
-    public final void resume() {
-        checkAccess();
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenThreadsLock) {
-            for (int i = 0; i < numThreads; i++) {
-                this.childrenThreads[i].resume();
-            }
-        }
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenGroupsLock) {
-            for (int i = 0; i < numGroups; i++) {
-                this.childrenGroups[i].resume();
-            }
-        }
-    }
-
-    /**
-     * Configures the receiver to be a daemon ThreadGroup or not. Daemon
-     * ThreadGroups are automatically destroyed when they become empty.
-     * 
-     * @param isDaemon new value defining if receiver should be daemon or not
-     * 
-     * @throws SecurityException if <code>checkAccess()</code> for the parent
-     *         group fails with a SecurityException
-     * 
-     * @see #isDaemon
-     * @see #destroy
-     */
-    public final void setDaemon(boolean isDaemon) {
-        checkAccess();
-        this.isDaemon = isDaemon;
-    }
-
-    /**
-     * Configures the maximum allowed priority for a Thread in the receiver and
-     * recursively in all its subgroups.
-     * 
-     * One can never change the maximum priority of a ThreadGroup to be higher
-     * than it was. Such an attempt will not result in an exception, it will
-     * simply leave the ThreadGroup with its current maximum priority.
-     * 
-     * @param newMax the new maximum priority to be set
-     * 
-     * @throws SecurityException if <code>checkAccess()</code> fails with a
-     *         SecurityException
-     * @throws IllegalArgumentException if the new priority is greater than
-     *         Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY
-     * 
-     * @see #getMaxPriority
-     */
-    public final void setMaxPriority(int newMax) {
-        checkAccess();
-
-        if (newMax <= this.maxPriority) {
-            if (newMax < Thread.MIN_PRIORITY) {
-                newMax = Thread.MIN_PRIORITY;
-            }
-
-            int parentPriority = parent == null ? newMax : parent.getMaxPriority();
-            this.maxPriority = parentPriority <= newMax ? parentPriority : newMax;
-            // Lock this subpart of the tree as we walk
-            synchronized (this.childrenGroupsLock) {
-                // ??? why not maxPriority
-                for (int i = 0; i < numGroups; i++) {
-                    this.childrenGroups[i].setMaxPriority(newMax);
-                }
-            }
-        }
-    }
-
-    /**
-     * Sets the parent ThreadGroup of the receiver, and adds the receiver to the
-     * parent's collection of immediate children (if <code>parent</code> is
-     * not <code>null</code>).
-     * 
-     * @param parent The parent ThreadGroup, or null if the receiver is to be
-     *        the root ThreadGroup
-     * 
-     * @see #getParent
-     * @see #parentOf
-     */
-    private void setParent(ThreadGroup parent) {
-        if (parent != null) {
-            parent.add(this);
-        }
-        this.parent = parent;
-    }
-
-    /**
-     * Stops every Thread in the receiver and recursively in all its subgroups.
-     * 
-     * @throws SecurityException if <code>this.checkAccess()</code> fails with
-     *         a SecurityException
-     * 
-     * @see Thread#stop()
-     * @see Thread#stop(Throwable)
-     * @see ThreadDeath
-     * 
-     * @deprecated Requires deprecated method Thread.stop().
-     */
-    @SuppressWarnings("deprecation")
-    @Deprecated
-    public final void stop() {
-        if (stopHelper()) {
-            Thread.currentThread().stop();
-        }
-    }
-
-    /**
-     * @deprecated Requires deprecated method Thread.suspend().
-     */
-    @SuppressWarnings("deprecation")
-    @Deprecated
-    private final boolean stopHelper() {
-        checkAccess();
-
-        boolean stopCurrent = false;
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenThreadsLock) {
-            Thread current = Thread.currentThread();
-            for (int i = 0; i < numThreads; i++) {
-                if (this.childrenThreads[i] == current) {
-                    stopCurrent = true;
-                } else {
-                    this.childrenThreads[i].stop();
-                }
-            }
-        }
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenGroupsLock) {
-            for (int i = 0; i < numGroups; i++) {
-                stopCurrent |= this.childrenGroups[i].stopHelper();
-            }
-        }
-        return stopCurrent;
-    }
-
-    /**
-     * Suspends every Thread in the receiver and recursively in all its
-     * subgroups.
-     * 
-     * @throws SecurityException if <code>this.checkAccess()</code> fails with
-     *         a SecurityException
-     * 
-     * @see Thread#suspend
-     * @see #resume
-     * 
-     * @deprecated Requires deprecated method Thread.suspend().
-     */
-    @SuppressWarnings("deprecation")
-    @Deprecated
-    public final void suspend() {
-        if (suspendHelper()) {
-            Thread.currentThread().suspend();
-        }
-    }
-
-    /**
-     * @deprecated Requires deprecated method Thread.suspend().
-     */
-    @SuppressWarnings("deprecation")
-    @Deprecated
-    private final boolean suspendHelper() {
-        checkAccess();
-
-        boolean suspendCurrent = false;
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenThreadsLock) {
-            Thread current = Thread.currentThread();
-            for (int i = 0; i < numThreads; i++) {
-                if (this.childrenThreads[i] == current) {
-                    suspendCurrent = true;
-                } else {
-                    this.childrenThreads[i].suspend();
-                }
-            }
-        }
-        // Lock this subpart of the tree as we walk
-        synchronized (this.childrenGroupsLock) {
-            for (int i = 0; i < numGroups; i++) {
-                suspendCurrent |= this.childrenGroups[i].suspendHelper();
-            }
-        }
-        return suspendCurrent;
-    }
-
-    /**
-     * Answers a string containing a concise, human-readable description of the
-     * receiver.
-     * 
-     * @return a printable representation for the receiver.
-     */
-    @Override
-    public String toString() {
-        return getClass().getName() + "[name=" + this.getName() + ",maxpri="
-                + this.getMaxPriority() + "]";
-    }
-
-    /**
-     * Any uncaught exception in any Thread has to be forwarded (by the VM) to
-     * the Thread's ThreadGroup by sending this message (uncaughtException).
-     * This allows users to define custom ThreadGroup classes and custom
-     * behavior for when a Thread has an uncaughtException or when it does
-     * (ThreadDeath).
-     * 
-     * @param t Thread with an uncaught exception
-     * @param e The uncaught exception itself
-     * 
-     * @see Thread#stop()
-     * @see Thread#stop(Throwable)
-     * @see ThreadDeath
-     */
-    public void uncaughtException(Thread t, Throwable e) {
-        if (parent != null) {
-            parent.uncaughtException(t, e);
-        } else if (!(e instanceof ThreadDeath)) {
-            // No parent group, has to be 'system' Thread Group
-            e.printStackTrace(System.err);
-        }
-    }
-}
+/* Copyright 1998, 2005 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.
+ */
+
+package java.lang;
+
+/**
+ * An implementation of this class is provided, but the documented constructors
+ * are used by the vm specific implementation to create the required "system"
+ * and "main" ThreadGroups. The documented methods are used by java.lang.Thread
+ * to add and remove Threads from their ThreadGroups.
+ * 
+ * ThreadGroups are containers of Threads and ThreadGroups, therefore providing
+ * a tree-like structure to organize Threads. The root ThreadGroup name is
+ * "system" and it has no parent ThreadGroup. All other ThreadGroups have
+ * exactly one parent ThreadGroup. All Threads belong to exactly one
+ * ThreadGroup.
+ * 
+ * @see Thread
+ * @see SecurityManager
+ */
+public class ThreadGroup implements Thread.UncaughtExceptionHandler {
+
+    // Name of this ThreadGroup
+    private String name;
+
+    // Maximum priority for Threads inside this ThreadGroup
+    private int maxPriority = Thread.MAX_PRIORITY;
+
+    // The ThreadGroup to which this ThreadGroup belongs
+    ThreadGroup parent;
+
+    int numThreads;
+
+    // The Threads this ThreadGroup contains
+    private Thread[] childrenThreads = new Thread[5];
+
+    // The number of children groups
+    int numGroups;
+
+    // The ThreadGroups this ThreadGroup contains
+    private ThreadGroup[] childrenGroups = new ThreadGroup[3];
+
+    // Locked when using the childrenGroups field
+    private Object childrenGroupsLock = new Object();
+
+    // Locked when using the childrenThreads field
+    private Object childrenThreadsLock = new Object();
+
+    // Whether this ThreadGroup is a daemon ThreadGroup or not
+    private boolean isDaemon;
+
+    // Whether this ThreadGroup has already been destroyed or not
+    private boolean isDestroyed;
+
+    /**
+     * Used by the JVM to create the "system" ThreadGroup. Construct a
+     * ThreadGroup instance, and assign the name "system".
+     */
+    private ThreadGroup() {
+        name = "system";
+    }
+
+    /**
+     * Constructs a new ThreadGroup with the name provided. The new ThreadGroup
+     * will be child of the ThreadGroup to which the
+     * <code>Thread.currentThread()</code> belongs.
+     * 
+     * @param name Name for the ThreadGroup being created
+     * 
+     * @throws SecurityException if <code>checkAccess()</code> for the parent
+     *         group fails with a SecurityException
+     * 
+     * @see java.lang.Thread#currentThread
+     */
+
+    public ThreadGroup(String name) {
+        this(Thread.currentThread().getThreadGroup(), name);
+    }
+
+    /**
+     * Constructs a new ThreadGroup with the name provided, as child of the
+     * ThreadGroup <code>parent</code>
+     * 
+     * @param parent Parent ThreadGroup
+     * @param name Name for the ThreadGroup being created
+     * 
+     * @throws NullPointerException if <code>parent</code> is
+     *         <code>null</code>
+     * @throws SecurityException if <code>checkAccess()</code> for the parent
+     *         group fails with a SecurityException
+     * @throws IllegalThreadStateException if <code>parent</code> has been
+     *         destroyed already
+     */
+    public ThreadGroup(ThreadGroup parent, String name) {
+        super();
+        if (Thread.currentThread() != null) {
+            // If parent is null we must throw NullPointerException, but that
+            // will be done "for free" with the message send below
+            parent.checkAccess();
+        }
+
+        this.name = name;
+        this.setParent(parent);
+        if (parent != null) {
+            this.setMaxPriority(parent.getMaxPriority());
+            if (parent.isDaemon()) {
+                this.setDaemon(true);
+            }
+        }
+    }
+
+    /**
+     * Initialize the "main" ThreadGroup
+     */
+    ThreadGroup(ThreadGroup parent) {
+        this.name = "main";
+        this.setParent(parent);
+    }
+
+    /**
+     * Returns the number of Threads which are children of the receiver,
+     * directly or indirectly.
+     * 
+     * @return Number of children Threads
+     */
+
+    public int activeCount() {
+        int count = numThreads;
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                count += this.childrenGroups[i].activeCount();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Returns the number of ThreadGroups which are children of the receiver,
+     * directly or indirectly.
+     * 
+     * @return Number of children ThreadGroups
+     */
+    public int activeGroupCount() {
+        int count = 0;
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                // One for this group & the subgroups
+                count += 1 + this.childrenGroups[i].activeGroupCount();
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Adds a Thread to the receiver. This should only be visible to class
+     * java.lang.Thread, and should only be called when a new Thread is created
+     * and initialized by the constructor.
+     * 
+     * @param thread Thread to add to the receiver
+     * 
+     * @throws IllegalThreadStateException if the receiver has been destroyed
+     *         already
+     * 
+     * @see #remove(java.lang.Thread)
+     */
+    final void add(Thread thread) throws IllegalThreadStateException {
+        synchronized (this.childrenThreadsLock) {
+            if (!isDestroyed) {
+                if (childrenThreads.length == numThreads) {
+                    Thread[] newThreads = new Thread[childrenThreads.length * 2];
+                    System.arraycopy(childrenThreads, 0, newThreads, 0, numThreads);
+                    newThreads[numThreads++] = thread;
+                    childrenThreads = newThreads;
+                } else {
+                    childrenThreads[numThreads++] = thread;
+                }
+            } else {
+                throw new IllegalThreadStateException();
+            }
+        }
+    }
+
+    /**
+     * Adds a ThreadGroup to the receiver.
+     * 
+     * @param g ThreadGroup to add to the receiver
+     * 
+     * @throws IllegalThreadStateException if the receiver has been destroyed
+     *         already
+     */
+    private void add(ThreadGroup g) throws IllegalThreadStateException {
+        synchronized (this.childrenGroupsLock) {
+            if (!isDestroyed) {
+                if (childrenGroups.length == numGroups) {
+                    ThreadGroup[] newGroups = new ThreadGroup[childrenGroups.length * 2];
+                    System.arraycopy(childrenGroups, 0, newGroups, 0, numGroups);
+                    newGroups[numGroups++] = g;
+                    childrenGroups = newGroups;
+                } else {
+                    childrenGroups[numGroups++] = g;
+                }
+            } else {
+                throw new IllegalThreadStateException();
+            }
+        }
+    }
+
+    /**
+     * The definition of this method depends on the deprecated method
+     * <code>suspend()</code>. The behavior of this call was never specified.
+     * 
+     * @param b Used to control low memory implicit suspension
+     * 
+     * @deprecated Required deprecated method suspend().
+     */
+    @Deprecated
+    public boolean allowThreadSuspension(boolean b) {
+        // Does not apply to this VM, no-op
+        return true;
+    }
+
+    /**
+     * If there is a SecurityManager installed, call <code>checkAccess</code>
+     * in it passing the receiver as parameter, otherwise do nothing.
+     */
+    public final void checkAccess() {
+        // Forwards the message to the SecurityManager (if there's one) passing
+        // the receiver as parameter
+        SecurityManager currentManager = System.getSecurityManager();
+        if (currentManager != null) {
+            currentManager.checkAccess(this);
+        }
+    }
+
+    /**
+     * Destroys the receiver and recursively all its subgroups. It is only legal
+     * to destroy a ThreadGroup that has no Threads. Any daemon ThreadGroup is
+     * destroyed automatically when it becomes empty (no Threads and no
+     * ThreadGroups in it).
+     * 
+     * @throws IllegalThreadStateException if the receiver or any of its
+     *         subgroups has been destroyed already
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     */
+
+    public final void destroy() {
+        checkAccess();
+
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            synchronized (this.childrenGroupsLock) {
+                int toDestroy = numGroups;
+                // Call recursively for subgroups
+                for (int i = 0; i < toDestroy; i++) {
+                    // We always get the first element - remember, when the
+                    // child dies it removes itself from our collection. See
+                    // below.
+                    this.childrenGroups[0].destroy();
+                }
+
+                if (parent != null) {
+                    parent.remove(this);
+                }
+
+                // Now that the ThreadGroup is really destroyed it can be tagged
+                // as so
+                this.isDestroyed = true;
+            }
+        }
+    }
+
+    /*
+     * Auxiliary method that destroys the receiver and recursively all its
+     * subgroups if the receiver is a daemon ThreadGroup.
+     * 
+     * @see #destroy
+     * @see #setDaemon
+     * @see #isDaemon
+     */
+    private void destroyIfEmptyDaemon() {
+        // Has to be non-destroyed daemon to make sense
+        synchronized (this.childrenThreadsLock) {
+            if (isDaemon && !isDestroyed && numThreads == 0) {
+                synchronized (this.childrenGroupsLock) {
+                    if (numGroups == 0) {
+                        destroy();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Copies an array with all Threads which are children of the receiver
+     * (directly or indirectly) into the array <code>threads</code> passed as
+     * parameters. If the array passed as parameter is too small no exception is
+     * thrown - the extra elements are simply not copied.
+     * 
+     * @param threads Thread array into which the Threads will be copied
+     * @return How many Threads were copied over
+     * 
+     */
+    public int enumerate(Thread[] threads) {
+        return enumerate(threads, true);
+    }
+
+    /**
+     * Copies an array with all Threads which are children of the receiver into
+     * the array <code>threads</code> passed as parameter. Children Threads of
+     * subgroups are recursively copied as well if parameter
+     * <code>recurse</code> is <code>true</code>.
+     * 
+     * If the array passed as parameter is too small no exception is thrown -
+     * the extra elements are simply not copied.
+     * 
+     * @param threads array into which the Threads will be copied
+     * @param recurse Indicates whether Threads in subgroups should be
+     *        recursively copied as well or not
+     * @return How many Threads were copied over
+     * 
+     */
+    public int enumerate(Thread[] threads, boolean recurse) {
+        return enumerateGeneric(threads, recurse, 0, true);
+    }
+
+    /**
+     * Copies an array with all ThreadGroups which are children of the receiver
+     * (directly or indirectly) into the array <code>groups</code> passed as
+     * parameters. If the array passed as parameter is too small no exception is
+     * thrown - the extra elements are simply not copied.
+     * 
+     * @param groups array into which the ThreadGroups will be copied
+     * @return How many ThreadGroups were copied over
+     * 
+     */
+    public int enumerate(ThreadGroup[] groups) {
+        return enumerate(groups, true);
+    }
+
+    /**
+     * Copies an array with all ThreadGroups which are children of the receiver
+     * into the array <code>groups</code> passed as parameter. Children
+     * ThreadGroups of subgroups are recursively copied as well if parameter
+     * <code>recurse</code> is <code>true</code>.
+     * 
+     * If the array passed as parameter is too small no exception is thrown -
+     * the extra elements are simply not copied.
+     * 
+     * @param groups array into which the ThreadGroups will be copied
+     * @param recurse Indicates whether ThreadGroups in subgroups should be
+     *        recursively copied as well or not
+     * @return How many ThreadGroups were copied over
+     * 
+     */
+    public int enumerate(ThreadGroup[] groups, boolean recurse) {
+        return enumerateGeneric(groups, recurse, 0, false);
+    }
+
+    /**
+     * Copies into <param>enumeration</param> starting at
+     * <param>enumerationIndex</param> all Threads or ThreadGroups in the
+     * receiver. If <param>recurse</param> is true, recursively enumerate the
+     * elements in subgroups.
+     * 
+     * If the array passed as parameter is too small no exception is thrown -
+     * the extra elements are simply not copied.
+     * 
+     * @param enumeration array into which the elements will be copied
+     * @param recurse Indicates whether subgroups should be enumerated or not
+     * @param enumerationIndex Indicates in which position of the enumeration
+     *        array we are
+     * @param enumeratingThreads Indicates whether we are enumerating Threads or
+     *        ThreadGroups
+     * @return How many elements were enumerated/copied over
+     */
+    private int enumerateGeneric(Object[] enumeration, boolean recurse, int enumerationIndex,
+            boolean enumeratingThreads) {
+        checkAccess();
+
+        Object[] immediateCollection = enumeratingThreads ? (Object[]) childrenThreads
+                : (Object[]) childrenGroups;
+        Object syncLock = enumeratingThreads ? childrenThreadsLock : childrenGroupsLock;
+
+        synchronized (syncLock) { // Lock this subpart of the tree as we walk
+            for (int i = enumeratingThreads ? numThreads : numGroups; --i >= 0;) {
+                if (!enumeratingThreads || ((Thread) immediateCollection[i]).isAlive()) {
+                    if (enumerationIndex >= enumeration.length) {
+                        return enumerationIndex;
+                    }
+                    enumeration[enumerationIndex++] = immediateCollection[i];
+                }
+            }
+        }
+
+        if (recurse) { // Lock this subpart of the tree as we walk
+            synchronized (this.childrenGroupsLock) {
+                for (int i = 0; i < numGroups; i++) {
+                    if (enumerationIndex >= enumeration.length) {
+                        return enumerationIndex;
+                    }
+                    enumerationIndex = childrenGroups[i].enumerateGeneric(enumeration, recurse,
+                            enumerationIndex, enumeratingThreads);
+                }
+            }
+        }
+        return enumerationIndex;
+    }
+
+    /**
+     * Answers the maximum allowed priority for a Thread in the receiver.
+     * 
+     * @return the maximum priority (an <code>int</code>)
+     * 
+     * @see #setMaxPriority
+     */
+    public final int getMaxPriority() {
+        return maxPriority;
+    }
+
+    /**
+     * Answers the name of the receiver.
+     * 
+     * @return the receiver's name (a java.lang.String)
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * Answers the receiver's parent ThreadGroup. It can be null if the receiver
+     * is the the root ThreadGroup.
+     * 
+     * @return the parent ThreadGroup
+     * 
+     */
+    public final ThreadGroup getParent() {
+        if (parent != null) {
+            parent.checkAccess();
+        }
+        return parent;
+    }
+
+    /**
+     * Interrupts every Thread in the receiver and recursively in all its
+     * subgroups.
+     * 
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     * 
+     * @see Thread#interrupt
+     */
+    public final void interrupt() {
+        checkAccess();
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            for (int i = 0; i < numThreads; i++) {
+                this.childrenThreads[i].interrupt();
+            }
+        }
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                this.childrenGroups[i].interrupt();
+            }
+        }
+    }
+
+    /**
+     * Answers true if the receiver is a daemon ThreadGroup, false otherwise.
+     * 
+     * @return if the receiver is a daemon ThreadGroup
+     * 
+     * @see #setDaemon
+     * @see #destroy
+     */
+    public final boolean isDaemon() {
+        return isDaemon;
+    }
+
+    /**
+     * Answers true if the receiver has been destroyed already, false otherwise.
+     * 
+     * @return if the receiver has been destroyed already
+     * 
+     * @see #destroy
+     */
+    public boolean isDestroyed() {
+        return isDestroyed;
+    }
+
+    /**
+     * Outputs to <code>System.out</code> a text representation of the
+     * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
+     * Proper identation is done to suggest the nesting of groups inside groups
+     * and threads inside groups.
+     */
+    public void list() {
+        // We start in a fresh line
+        System.out.println();
+        list(0);
+    }
+
+    /*
+     * Outputs to <code>System.out</code>a text representation of the
+     * hierarchy of Threads and ThreadGroups in the receiver (and recursively).
+     * The identation will be four spaces per level of nesting.
+     * 
+     * @param levels How many levels of nesting, so that proper identetion can
+     * be output.
+     */
+    private void list(int levels) {
+        for (int i = 0; i < levels; i++) {
+            System.out.print("    "); // 4 spaces for each level
+        }
+
+        // Print the receiver
+        System.out.println(this.toString());
+
+        // Print the children threads, with 1 extra identation
+        synchronized (this.childrenThreadsLock) {
+            for (int i = 0; i < numThreads; i++) {
+                // children get an extra identation, 4 spaces for each level
+                for (int j = 0; j <= levels; j++) {
+                    System.out.print("    ");
+                }
+                System.out.println(this.childrenThreads[i]);
+            }
+        }
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                this.childrenGroups[i].list(levels + 1);
+            }
+        }
+    }
+
+    /**
+     * Answers true if the receiver is a direct or indirect parent group of
+     * ThreadGroup <code>g</code>, false otherwise.
+     * 
+     * @param g ThreadGroup to test
+     * 
+     * @return if the receiver is parent of the ThreadGroup passed as parameter
+     * 
+     */
+    public final boolean parentOf(ThreadGroup g) {
+        while (g != null) {
+            if (this == g) {
+                return true;
+            }
+            g = g.parent;
+        }
+        return false;
+    }
+
+    /**
+     * Removes a Thread from the receiver. This should only be visible to class
+     * java.lang.Thread, and should only be called when a Thread dies.
+     * 
+     * @param thread Thread to remove from the receiver
+     * 
+     * @see #add(Thread)
+     */
+    final void remove(java.lang.Thread thread) {
+        synchronized (this.childrenThreadsLock) {
+            for (int i = 0; i < numThreads; i++) {
+                if (childrenThreads[i].equals(thread)) {
+                    numThreads--;
+                    System
+                            .arraycopy(childrenThreads, i + 1, childrenThreads, i, numThreads
+                                    - i);
+                    childrenThreads[numThreads] = null;
+                    break;
+                }
+            }
+        }
+        destroyIfEmptyDaemon();
+    }
+
+    /**
+     * Removes an immediate subgroup from the receiver.
+     * 
+     * @param g Threadgroup to remove from the receiver
+     * 
+     * @see #add(Thread)
+     * @see #add(ThreadGroup)
+     */
+    private void remove(ThreadGroup g) {
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                if (childrenGroups[i].equals(g)) {
+                    numGroups--;
+                    System.arraycopy(childrenGroups, i + 1, childrenGroups, i, numGroups - i);
+                    childrenGroups[numGroups] = null;
+                    break;
+                }
+            }
+        }
+        destroyIfEmptyDaemon();
+    }
+
+    /**
+     * Resumes every Thread in the receiver and recursively in all its
+     * subgroups.
+     * 
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     * 
+     * @see Thread#resume
+     * @see #suspend
+     * 
+     * @deprecated Requires deprecated method Thread.resume().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void resume() {
+        checkAccess();
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            for (int i = 0; i < numThreads; i++) {
+                this.childrenThreads[i].resume();
+            }
+        }
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                this.childrenGroups[i].resume();
+            }
+        }
+    }
+
+    /**
+     * Configures the receiver to be a daemon ThreadGroup or not. Daemon
+     * ThreadGroups are automatically destroyed when they become empty.
+     * 
+     * @param isDaemon new value defining if receiver should be daemon or not
+     * 
+     * @throws SecurityException if <code>checkAccess()</code> for the parent
+     *         group fails with a SecurityException
+     * 
+     * @see #isDaemon
+     * @see #destroy
+     */
+    public final void setDaemon(boolean isDaemon) {
+        checkAccess();
+        this.isDaemon = isDaemon;
+    }
+
+    /**
+     * Configures the maximum allowed priority for a Thread in the receiver and
+     * recursively in all its subgroups.
+     * 
+     * One can never change the maximum priority of a ThreadGroup to be higher
+     * than it was. Such an attempt will not result in an exception, it will
+     * simply leave the ThreadGroup with its current maximum priority.
+     * 
+     * @param newMax the new maximum priority to be set
+     * 
+     * @throws SecurityException if <code>checkAccess()</code> fails with a
+     *         SecurityException
+     * @throws IllegalArgumentException if the new priority is greater than
+     *         Thread.MAX_PRIORITY or less than Thread.MIN_PRIORITY
+     * 
+     * @see #getMaxPriority
+     */
+    public final void setMaxPriority(int newMax) {
+        checkAccess();
+
+        if (newMax <= this.maxPriority) {
+            if (newMax < Thread.MIN_PRIORITY) {
+                newMax = Thread.MIN_PRIORITY;
+            }
+
+            int parentPriority = parent == null ? newMax : parent.getMaxPriority();
+            this.maxPriority = parentPriority <= newMax ? parentPriority : newMax;
+            // Lock this subpart of the tree as we walk
+            synchronized (this.childrenGroupsLock) {
+                // ??? why not maxPriority
+                for (int i = 0; i < numGroups; i++) {
+                    this.childrenGroups[i].setMaxPriority(newMax);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the parent ThreadGroup of the receiver, and adds the receiver to the
+     * parent's collection of immediate children (if <code>parent</code> is
+     * not <code>null</code>).
+     * 
+     * @param parent The parent ThreadGroup, or null if the receiver is to be
+     *        the root ThreadGroup
+     * 
+     * @see #getParent
+     * @see #parentOf
+     */
+    private void setParent(ThreadGroup parent) {
+        if (parent != null) {
+            parent.add(this);
+        }
+        this.parent = parent;
+    }
+
+    /**
+     * Stops every Thread in the receiver and recursively in all its subgroups.
+     * 
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     * 
+     * @see Thread#stop()
+     * @see Thread#stop(Throwable)
+     * @see ThreadDeath
+     * 
+     * @deprecated Requires deprecated method Thread.stop().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void stop() {
+        if (stopHelper()) {
+            Thread.currentThread().stop();
+        }
+    }
+
+    /**
+     * @deprecated Requires deprecated method Thread.suspend().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    private final boolean stopHelper() {
+        checkAccess();
+
+        boolean stopCurrent = false;
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            Thread current = Thread.currentThread();
+            for (int i = 0; i < numThreads; i++) {
+                if (this.childrenThreads[i] == current) {
+                    stopCurrent = true;
+                } else {
+                    this.childrenThreads[i].stop();
+                }
+            }
+        }
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                stopCurrent |= this.childrenGroups[i].stopHelper();
+            }
+        }
+        return stopCurrent;
+    }
+
+    /**
+     * Suspends every Thread in the receiver and recursively in all its
+     * subgroups.
+     * 
+     * @throws SecurityException if <code>this.checkAccess()</code> fails with
+     *         a SecurityException
+     * 
+     * @see Thread#suspend
+     * @see #resume
+     * 
+     * @deprecated Requires deprecated method Thread.suspend().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    public final void suspend() {
+        if (suspendHelper()) {
+            Thread.currentThread().suspend();
+        }
+    }
+
+    /**
+     * @deprecated Requires deprecated method Thread.suspend().
+     */
+    @SuppressWarnings("deprecation")
+    @Deprecated
+    private final boolean suspendHelper() {
+        checkAccess();
+
+        boolean suspendCurrent = false;
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenThreadsLock) {
+            Thread current = Thread.currentThread();
+            for (int i = 0; i < numThreads; i++) {
+                if (this.childrenThreads[i] == current) {
+                    suspendCurrent = true;
+                } else {
+                    this.childrenThreads[i].suspend();
+                }
+            }
+        }
+        // Lock this subpart of the tree as we walk
+        synchronized (this.childrenGroupsLock) {
+            for (int i = 0; i < numGroups; i++) {
+                suspendCurrent |= this.childrenGroups[i].suspendHelper();
+            }
+        }
+        return suspendCurrent;
+    }
+
+    /**
+     * Answers a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return a printable representation for the receiver.
+     */
+    @Override
+    public String toString() {
+        return getClass().getName() + "[name=" + this.getName() + ",maxpri="
+                + this.getMaxPriority() + "]";
+    }
+
+    /**
+     * Any uncaught exception in any Thread has to be forwarded (by the VM) to
+     * the Thread's ThreadGroup by sending this message (uncaughtException).
+     * This allows users to define custom ThreadGroup classes and custom
+     * behavior for when a Thread has an uncaughtException or when it does
+     * (ThreadDeath).
+     * 
+     * @param t Thread with an uncaught exception
+     * @param e The uncaught exception itself
+     * 
+     * @see Thread#stop()
+     * @see Thread#stop(Throwable)
+     * @see ThreadDeath
+     */
+    public void uncaughtException(Thread t, Throwable e) {
+        if (parent != null) {
+            parent.uncaughtException(t, e);
+        } else if (!(e instanceof ThreadDeath)) {
+            // No parent group, has to be 'system' Thread Group
+            e.printStackTrace(System.err);
+        }
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ThreadGroup.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java?view=diff&rev=446491&r1=446490&r2=446491
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java Thu Sep 14 20:08:07 2006
@@ -1,341 +1,341 @@
-/* Copyright 1998, 2005 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.
- */
-
-package java.lang;
-
-import java.io.IOException;
-import java.io.ObjectOutputStream;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-
-/**
- * This class must be implemented by the VM vendor, or the reference
- * implementation can be used if the documented natives are implemented.
- * 
- * This class is the superclass of all classes which can be thrown by the
- * virtual machine. The two direct subclasses represent recoverable exceptions
- * (Exception) and unrecoverable errors (Error). This class provides common
- * methods for accessing a string message which provides extra information about
- * the circumstances in which the throwable was created, and for filling in a
- * walkback (i.e. a record of the call stack at a particular point in time)
- * which can be printed later.
- * 
- * @see Error
- * @see Exception
- * @see RuntimeException
- */
-public class Throwable implements java.io.Serializable {
-    private static final long serialVersionUID = -3042686055658047285L;
-
-    /**
-     * The message provided when the exception was created.
-     */
-    private String detailMessage;
-
-    /**
-     * The cause of this Throwable. Null when there is no cause.
-     */
-    private Throwable cause = this;
-
-    private StackTraceElement[] stackTrace;
-
-    /**
-     * Constructs a new instance of this class with its walkback filled in.
-     */
-    public Throwable() {
-        super();
-        fillInStackTrace();
-    }
-
-    /**
-     * Constructs a new instance of this class with its walkback and message
-     * filled in.
-     * 
-     * @param detailMessage String The detail message for the exception.
-     */
-    public Throwable(String detailMessage) {
-        this();
-        this.detailMessage = detailMessage;
-    }
-
-    /**
-     * Constructs a new instance of this class with its walkback, message and
-     * cause filled in.
-     * 
-     * @param detailMessage String The detail message for the exception.
-     * @param throwable The cause of this Throwable
-     */
-    public Throwable(String detailMessage, Throwable throwable) {
-        this();
-        this.detailMessage = detailMessage;
-        cause = throwable;
-    }
-
-    /**
-     * Constructs a new instance of this class with its walkback and cause
-     * filled in.
-     * 
-     * @param throwable The cause of this Throwable
-     */
-    public Throwable(Throwable throwable) {
-        this();
-        this.detailMessage = throwable == null ? null : throwable.toString();
-        cause = throwable;
-    }
-
-    /**
-     * This native must be implemented to use the reference implementation of
-     * this class.
-     * 
-     * Record in the receiver a walkback from the point where this message was
-     * sent. The message is public so that code which catches a throwable and
-     * then <em>re-throws</em> it can adjust the walkback to represent the
-     * location where the exception was re-thrown.
-     * 
-     * @return the receiver
-     */
-    public native Throwable fillInStackTrace();
-
-    /**
-     * Answers the extra information message which was provided when the
-     * throwable was created. If no message was provided at creation time, then
-     * answer null.
-     * 
-     * @return String The receiver's message.
-     */
-    public String getMessage() {
-        return detailMessage;
-    }
-
-    /**
-     * Answers the extra information message which was provided when the
-     * throwable was created. If no message was provided at creation time, then
-     * answer null. Subclasses may override this method to answer localized text
-     * for the message.
-     * 
-     * @return String The receiver's message.
-     */
-    public String getLocalizedMessage() {
-        return getMessage();
-    }
-
-    /**
-     * This native must be implemented to use the reference implementation of
-     * this class. The result of this native is cloned, and returned from the
-     * public API getStackTrace().
-     * 
-     * Answers an array of StackTraceElement. Each StackTraceElement represents
-     * a entry on the stack.
-     * 
-     * @return an array of StackTraceElement representing the stack
-     */
-    private native StackTraceElement[] getStackTraceImpl();
-
-    /**
-     * Answers an array of StackTraceElement. Each StackTraceElement represents
-     * a entry on the stack.
-     * 
-     * @return an array of StackTraceElement representing the stack
-     */
-    public StackTraceElement[] getStackTrace() {
-        return getInternalStackTrace().clone();
-    }
-
-    /**
-     * Sets the array of StackTraceElements. Each StackTraceElement represents a
-     * entry on the stack. A copy of this array will be returned by
-     * getStackTrace() and printed by printStackTrace().
-     * 
-     * @param trace The array of StackTraceElement
-     */
-    public void setStackTrace(StackTraceElement[] trace) {
-        StackTraceElement[] newTrace = trace.clone();
-        for (java.lang.StackTraceElement element : newTrace) {
-            if (element == null) {
-                throw new NullPointerException();
-            }
-        }
-        stackTrace = newTrace;
-    }
-
-    /**
-     * Outputs a printable representation of the receiver's walkback on the
-     * System.err stream.
-     */
-    public void printStackTrace() {
-        printStackTrace(System.err);
-    }
-
-    /**
-     * Count the number of duplicate stack frames, starting from the end of the
-     * stack.
-     * 
-     * @param currentStack a stack to compare
-     * @param parentStack a stack to compare
-     * 
-     * @return the number of duplicate stack frames.
-     */
-    private static int countDuplicates(StackTraceElement[] currentStack,
-            StackTraceElement[] parentStack) {
-        int duplicates = 0;
-        int parentIndex = parentStack.length;
-        for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
-            StackTraceElement parentFrame = parentStack[parentIndex];
-            if (parentFrame.equals(currentStack[i])) {
-                duplicates++;
-            } else {
-                break;
-            }
-        }
-        return duplicates;
-    }
-
-    /**
-     * Answers an array of StackTraceElement. Each StackTraceElement represents
-     * a entry on the stack. Cache the stack trace in the stackTrace field,
-     * returning the cached field when it has already been initialized.
-     * 
-     * @return an array of StackTraceElement representing the stack
-     */
-    private StackTraceElement[] getInternalStackTrace() {
-        if (stackTrace == null) {
-            stackTrace = getStackTraceImpl();
-        }
-        return stackTrace;
-    }
-
-    /**
-     * Outputs a printable representation of the receiver's walkback on the
-     * stream specified by the argument.
-     * 
-     * @param err PrintStream The stream to write the walkback on.
-     */
-    public void printStackTrace(PrintStream err) {
-        err.println(toString());
-        // Don't use getStackTrace() as it calls clone()
-        // Get stackTrace, in case stackTrace is reassigned
-        StackTraceElement[] stack = getInternalStackTrace();
-        for (java.lang.StackTraceElement element : stack) {
-            err.println("\tat " + element);
-        }
-
-        StackTraceElement[] parentStack = stack;
-        Throwable throwable = getCause();
-        while (throwable != null) {
-            err.print("Caused by: ");
-            err.println(throwable);
-            StackTraceElement[] currentStack = throwable.getInternalStackTrace();
-            int duplicates = countDuplicates(currentStack, parentStack);
-            for (int i = 0; i < currentStack.length - duplicates; i++) {
-                err.println("\tat " + currentStack[i]);
-            }
-            if (duplicates > 0) {
-                err.println("\t... " + duplicates + " more");
-            }
-            parentStack = currentStack;
-            throwable = throwable.getCause();
-        }
-    }
-
-    /**
-     * Outputs a printable representation of the receiver's walkback on the
-     * writer specified by the argument.
-     * 
-     * @param err PrintWriter The writer to write the walkback on.
-     */
-    public void printStackTrace(PrintWriter err) {
-        err.println(toString());
-        // Don't use getStackTrace() as it calls clone()
-        // Get stackTrace, in case stackTrace is reassigned
-        StackTraceElement[] stack = getInternalStackTrace();
-        for (java.lang.StackTraceElement element : stack) {
-            err.println("\tat " + element);
-        }
-
-        StackTraceElement[] parentStack = stack;
-        Throwable throwable = getCause();
-        while (throwable != null) {
-            err.print("Caused by: ");
-            err.println(throwable);
-            StackTraceElement[] currentStack = throwable.getInternalStackTrace();
-            int duplicates = countDuplicates(currentStack, parentStack);
-            for (int i = 0; i < currentStack.length - duplicates; i++) {
-                err.println("\tat " + currentStack[i]);
-            }
-            if (duplicates > 0) {
-                err.println("\t... " + duplicates + " more");
-            }
-            parentStack = currentStack;
-            throwable = throwable.getCause();
-        }
-    }
-
-    /**
-     * Answers a string containing a concise, human-readable description of the
-     * receiver.
-     * 
-     * @return String a printable representation for the receiver.
-     */
-    @Override
-    public String toString() {
-        String msg = getLocalizedMessage();
-        String name = getClass().getName();
-        if (msg == null) {
-            return name;
-        }
-        return new StringBuffer(name.length() + 2 + msg.length()).append(name).append(": ")
-                .append(msg).toString();
-    }
-
-    /**
-     * Initialize the cause of the receiver. The cause cannot be reassigned.
-     * 
-     * @param throwable The cause of this Throwable
-     * 
-     * @exception IllegalArgumentException when the cause is the receiver
-     * @exception IllegalStateException when the cause has already been
-     *            initialized
-     * 
-     * @return the receiver.
-     */
-    public synchronized Throwable initCause(Throwable throwable) {
-        if (cause == this) {
-            if (throwable != this) {
-                cause = throwable;
-                return this;
-            }
-            throw new IllegalArgumentException("Cause cannot be the receiver");
-        }
-        throw new IllegalStateException("Cause already initialized");
-    }
-
-    /**
-     * Answers the cause of this Throwable, or null if there is no cause.
-     * 
-     * @return Throwable The receiver's cause.
-     */
-    public Throwable getCause() {
-        if (cause == this) {
-            return null;
-        }
-        return cause;
-    }
-
-    private void writeObject(ObjectOutputStream s) throws IOException {
-        // ensure the stackTrace field is initialized
-        getInternalStackTrace();
-        s.defaultWriteObject();
-    }
-}
+/* Copyright 1998, 2005 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.
+ */
+
+package java.lang;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * This class must be implemented by the VM vendor, or the reference
+ * implementation can be used if the documented natives are implemented.
+ * 
+ * This class is the superclass of all classes which can be thrown by the
+ * virtual machine. The two direct subclasses represent recoverable exceptions
+ * (Exception) and unrecoverable errors (Error). This class provides common
+ * methods for accessing a string message which provides extra information about
+ * the circumstances in which the throwable was created, and for filling in a
+ * walkback (i.e. a record of the call stack at a particular point in time)
+ * which can be printed later.
+ * 
+ * @see Error
+ * @see Exception
+ * @see RuntimeException
+ */
+public class Throwable implements java.io.Serializable {
+    private static final long serialVersionUID = -3042686055658047285L;
+
+    /**
+     * The message provided when the exception was created.
+     */
+    private String detailMessage;
+
+    /**
+     * The cause of this Throwable. Null when there is no cause.
+     */
+    private Throwable cause = this;
+
+    private StackTraceElement[] stackTrace;
+
+    /**
+     * Constructs a new instance of this class with its walkback filled in.
+     */
+    public Throwable() {
+        super();
+        fillInStackTrace();
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback and message
+     * filled in.
+     * 
+     * @param detailMessage String The detail message for the exception.
+     */
+    public Throwable(String detailMessage) {
+        this();
+        this.detailMessage = detailMessage;
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback, message and
+     * cause filled in.
+     * 
+     * @param detailMessage String The detail message for the exception.
+     * @param throwable The cause of this Throwable
+     */
+    public Throwable(String detailMessage, Throwable throwable) {
+        this();
+        this.detailMessage = detailMessage;
+        cause = throwable;
+    }
+
+    /**
+     * Constructs a new instance of this class with its walkback and cause
+     * filled in.
+     * 
+     * @param throwable The cause of this Throwable
+     */
+    public Throwable(Throwable throwable) {
+        this();
+        this.detailMessage = throwable == null ? null : throwable.toString();
+        cause = throwable;
+    }
+
+    /**
+     * This native must be implemented to use the reference implementation of
+     * this class.
+     * 
+     * Record in the receiver a walkback from the point where this message was
+     * sent. The message is public so that code which catches a throwable and
+     * then <em>re-throws</em> it can adjust the walkback to represent the
+     * location where the exception was re-thrown.
+     * 
+     * @return the receiver
+     */
+    public native Throwable fillInStackTrace();
+
+    /**
+     * Answers the extra information message which was provided when the
+     * throwable was created. If no message was provided at creation time, then
+     * answer null.
+     * 
+     * @return String The receiver's message.
+     */
+    public String getMessage() {
+        return detailMessage;
+    }
+
+    /**
+     * Answers the extra information message which was provided when the
+     * throwable was created. If no message was provided at creation time, then
+     * answer null. Subclasses may override this method to answer localized text
+     * for the message.
+     * 
+     * @return String The receiver's message.
+     */
+    public String getLocalizedMessage() {
+        return getMessage();
+    }
+
+    /**
+     * This native must be implemented to use the reference implementation of
+     * this class. The result of this native is cloned, and returned from the
+     * public API getStackTrace().
+     * 
+     * Answers an array of StackTraceElement. Each StackTraceElement represents
+     * a entry on the stack.
+     * 
+     * @return an array of StackTraceElement representing the stack
+     */
+    private native StackTraceElement[] getStackTraceImpl();
+
+    /**
+     * Answers an array of StackTraceElement. Each StackTraceElement represents
+     * a entry on the stack.
+     * 
+     * @return an array of StackTraceElement representing the stack
+     */
+    public StackTraceElement[] getStackTrace() {
+        return getInternalStackTrace().clone();
+    }
+
+    /**
+     * Sets the array of StackTraceElements. Each StackTraceElement represents a
+     * entry on the stack. A copy of this array will be returned by
+     * getStackTrace() and printed by printStackTrace().
+     * 
+     * @param trace The array of StackTraceElement
+     */
+    public void setStackTrace(StackTraceElement[] trace) {
+        StackTraceElement[] newTrace = trace.clone();
+        for (java.lang.StackTraceElement element : newTrace) {
+            if (element == null) {
+                throw new NullPointerException();
+            }
+        }
+        stackTrace = newTrace;
+    }
+
+    /**
+     * Outputs a printable representation of the receiver's walkback on the
+     * System.err stream.
+     */
+    public void printStackTrace() {
+        printStackTrace(System.err);
+    }
+
+    /**
+     * Count the number of duplicate stack frames, starting from the end of the
+     * stack.
+     * 
+     * @param currentStack a stack to compare
+     * @param parentStack a stack to compare
+     * 
+     * @return the number of duplicate stack frames.
+     */
+    private static int countDuplicates(StackTraceElement[] currentStack,
+            StackTraceElement[] parentStack) {
+        int duplicates = 0;
+        int parentIndex = parentStack.length;
+        for (int i = currentStack.length; --i >= 0 && --parentIndex >= 0;) {
+            StackTraceElement parentFrame = parentStack[parentIndex];
+            if (parentFrame.equals(currentStack[i])) {
+                duplicates++;
+            } else {
+                break;
+            }
+        }
+        return duplicates;
+    }
+
+    /**
+     * Answers an array of StackTraceElement. Each StackTraceElement represents
+     * a entry on the stack. Cache the stack trace in the stackTrace field,
+     * returning the cached field when it has already been initialized.
+     * 
+     * @return an array of StackTraceElement representing the stack
+     */
+    private StackTraceElement[] getInternalStackTrace() {
+        if (stackTrace == null) {
+            stackTrace = getStackTraceImpl();
+        }
+        return stackTrace;
+    }
+
+    /**
+     * Outputs a printable representation of the receiver's walkback on the
+     * stream specified by the argument.
+     * 
+     * @param err PrintStream The stream to write the walkback on.
+     */
+    public void printStackTrace(PrintStream err) {
+        err.println(toString());
+        // Don't use getStackTrace() as it calls clone()
+        // Get stackTrace, in case stackTrace is reassigned
+        StackTraceElement[] stack = getInternalStackTrace();
+        for (java.lang.StackTraceElement element : stack) {
+            err.println("\tat " + element);
+        }
+
+        StackTraceElement[] parentStack = stack;
+        Throwable throwable = getCause();
+        while (throwable != null) {
+            err.print("Caused by: ");
+            err.println(throwable);
+            StackTraceElement[] currentStack = throwable.getInternalStackTrace();
+            int duplicates = countDuplicates(currentStack, parentStack);
+            for (int i = 0; i < currentStack.length - duplicates; i++) {
+                err.println("\tat " + currentStack[i]);
+            }
+            if (duplicates > 0) {
+                err.println("\t... " + duplicates + " more");
+            }
+            parentStack = currentStack;
+            throwable = throwable.getCause();
+        }
+    }
+
+    /**
+     * Outputs a printable representation of the receiver's walkback on the
+     * writer specified by the argument.
+     * 
+     * @param err PrintWriter The writer to write the walkback on.
+     */
+    public void printStackTrace(PrintWriter err) {
+        err.println(toString());
+        // Don't use getStackTrace() as it calls clone()
+        // Get stackTrace, in case stackTrace is reassigned
+        StackTraceElement[] stack = getInternalStackTrace();
+        for (java.lang.StackTraceElement element : stack) {
+            err.println("\tat " + element);
+        }
+
+        StackTraceElement[] parentStack = stack;
+        Throwable throwable = getCause();
+        while (throwable != null) {
+            err.print("Caused by: ");
+            err.println(throwable);
+            StackTraceElement[] currentStack = throwable.getInternalStackTrace();
+            int duplicates = countDuplicates(currentStack, parentStack);
+            for (int i = 0; i < currentStack.length - duplicates; i++) {
+                err.println("\tat " + currentStack[i]);
+            }
+            if (duplicates > 0) {
+                err.println("\t... " + duplicates + " more");
+            }
+            parentStack = currentStack;
+            throwable = throwable.getCause();
+        }
+    }
+
+    /**
+     * Answers a string containing a concise, human-readable description of the
+     * receiver.
+     * 
+     * @return String a printable representation for the receiver.
+     */
+    @Override
+    public String toString() {
+        String msg = getLocalizedMessage();
+        String name = getClass().getName();
+        if (msg == null) {
+            return name;
+        }
+        return new StringBuffer(name.length() + 2 + msg.length()).append(name).append(": ")
+                .append(msg).toString();
+    }
+
+    /**
+     * Initialize the cause of the receiver. The cause cannot be reassigned.
+     * 
+     * @param throwable The cause of this Throwable
+     * 
+     * @exception IllegalArgumentException when the cause is the receiver
+     * @exception IllegalStateException when the cause has already been
+     *            initialized
+     * 
+     * @return the receiver.
+     */
+    public synchronized Throwable initCause(Throwable throwable) {
+        if (cause == this) {
+            if (throwable != this) {
+                cause = throwable;
+                return this;
+            }
+            throw new IllegalArgumentException("Cause cannot be the receiver");
+        }
+        throw new IllegalStateException("Cause already initialized");
+    }
+
+    /**
+     * Answers the cause of this Throwable, or null if there is no cause.
+     * 
+     * @return Throwable The receiver's cause.
+     */
+    public Throwable getCause() {
+        if (cause == this) {
+            return null;
+        }
+        return cause;
+    }
+
+    private void writeObject(ObjectOutputStream s) throws IOException {
+        // ensure the stackTrace field is initialized
+        getInternalStackTrace();
+        s.defaultWriteObject();
+    }
+}

Propchange: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/Throwable.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ref/PhantomReference.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ref/PhantomReference.java?view=diff&rev=446491&r1=446490&r2=446491
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ref/PhantomReference.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni-kernel/src/main/java/java/lang/ref/PhantomReference.java Thu Sep 14 20:08:07 2006
@@ -1,48 +1,48 @@
-/* Copyright 1998, 2004 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.
- */
-
-package java.lang.ref;
-
-/**
- * PhantomReference objects are used to detect referents which are no longer
- * visible and are eligible to have their storage reclaimed.
- * 
- * @since 1.2
- */
-public class PhantomReference<T> extends Reference<T> {
-
-    /**
-     * Constructs a new instance of this class.
-     * 
-     * 
-     * @param r referent to track.
-     * @param q queue to register to the reference object with.
-     */
-    public PhantomReference(T r, ReferenceQueue<? super T> q) {
-        super();
-        initReference(r, q);
-    }
-
-    /**
-     * Return the referent of the reference object. Phantom reference objects
-     * referents are inaccessible, and so null is returned.
-     * 
-     * @return Object Returns null.
-     */
-    @Override
-    public T get() {
-        return super.get();
-    }
-}
+/* Copyright 1998, 2004 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.
+ */
+
+package java.lang.ref;
+
+/**
+ * PhantomReference objects are used to detect referents which are no longer
+ * visible and are eligible to have their storage reclaimed.
+ * 
+ * @since 1.2
+ */
+public class PhantomReference<T> extends Reference<T> {
+
+    /**
+     * Constructs a new instance of this class.
+     * 
+     * 
+     * @param r referent to track.
+     * @param q queue to register to the reference object with.
+     */
+    public PhantomReference(T r, ReferenceQueue<? super T> q) {
+        super();
+        initReference(r, q);
+    }
+
+    /**
+     * Return the referent of the reference object. Phantom reference objects
+     * referents are inaccessible, and so null is returned.
+     * 
+     * @return Object Returns null.
+     */
+    @Override
+    public T get() {
+        return super.get();
+    }
+}



Mime
View raw message