Merge "Print errors encountered while writing XML reports"
diff --git a/luni/src/main/java/java/lang/Double.java b/luni/src/main/java/java/lang/Double.java
index d6ad58e..95c7b81 100644
--- a/luni/src/main/java/java/lang/Double.java
+++ b/luni/src/main/java/java/lang/Double.java
@@ -174,11 +174,13 @@
     }
 
     /**
-     * Compares this object with the specified object and indicates if they are
-     * equal. In order to be equal, {@code object} must be an instance of
-     * {@code Double} and the bit pattern of its double value is the same as
-     * this object's.
-     *
+     * Tests this double for equality with {@code object}.
+     * To be equal, {@code object} must be an instance of {@code Double} and
+     * {@code doubleToLongBits} must give the same value for both objects.
+     * 
+     * <p>Note that, unlike {@code ==}, {@code -0.0} and {@code +0.0} compare
+     * unequal, and {@code NaN}s compare equal by this method.
+     * 
      * @param object
      *            the object to compare this double with.
      * @return {@code true} if the specified object is equal to this
diff --git a/luni/src/main/java/java/lang/Float.java b/luni/src/main/java/java/lang/Float.java
index 92b1731..54cc246 100644
--- a/luni/src/main/java/java/lang/Float.java
+++ b/luni/src/main/java/java/lang/Float.java
@@ -144,10 +144,13 @@
     }
 
     /**
-     * Compares this instance with the specified object and indicates if they
-     * are equal. In order to be equal, {@code object} must be an instance of
-     * {@code Float} and have the same float value as this object.
-     *
+     * Tests this double for equality with {@code object}.
+     * To be equal, {@code object} must be an instance of {@code Float} and
+     * {@code floatToIntBits} must give the same value for both objects.
+     * 
+     * <p>Note that, unlike {@code ==}, {@code -0.0} and {@code +0.0} compare
+     * unequal, and {@code NaN}s compare equal by this method.
+     * 
      * @param object
      *            the object to compare this float with.
      * @return {@code true} if the specified object is equal to this
diff --git a/luni/src/main/java/java/lang/Integer.java b/luni/src/main/java/java/lang/Integer.java
index 34b9c16..63cd615 100644
--- a/luni/src/main/java/java/lang/Integer.java
+++ b/luni/src/main/java/java/lang/Integer.java
@@ -610,15 +610,20 @@
     }
 
     /**
-     * Converts the specified integer into a string representation based on the
+     * Converts the specified signed integer into a string representation based on the
      * specified radix. The returned string is a concatenation of a minus sign
      * if the number is negative and characters from '0' to '9' and 'a' to 'z',
      * depending on the radix. If {@code radix} is not in the interval defined
      * by {@code Character.MIN_RADIX} and {@code Character.MAX_RADIX} then 10 is
      * used as the base for the conversion.
+     * 
+     * <p>This method treats its argument as signed. If you want to convert an
+     * unsigned value to one of the common non-decimal bases, you may find
+     * {@link #toBinaryString}, {@code #toHexString}, or {@link #toOctalString}
+     * more convenient.
      *
      * @param i
-     *            the integer to convert.
+     *            the signed integer to convert.
      * @param radix
      *            the base to use for the conversion.
      * @return the string representation of {@code i}.
diff --git a/luni/src/main/java/java/lang/Iterable.java b/luni/src/main/java/java/lang/Iterable.java
index 31883fb0..193fb7b 100644
--- a/luni/src/main/java/java/lang/Iterable.java
+++ b/luni/src/main/java/java/lang/Iterable.java
@@ -19,8 +19,8 @@
 import java.util.Iterator;
 
 /**
- * Objects of classes that implement this interface can be used within a
- * {@code foreach} statement.
+ * Instances of classes that implement this interface can be used with
+ * the enhanced for loop.
  *
  * @since 1.5
  */
diff --git a/luni/src/main/java/java/lang/Long.java b/luni/src/main/java/java/lang/Long.java
index 1c52896..2cc4cd7 100644
--- a/luni/src/main/java/java/lang/Long.java
+++ b/luni/src/main/java/java/lang/Long.java
@@ -583,15 +583,20 @@
     }
 
     /**
-     * Converts the specified long value into a string representation based on
+     * Converts the specified signed long value into a string representation based on
      * the specified radix. The returned string is a concatenation of a minus
      * sign if the number is negative and characters from '0' to '9' and 'a' to
      * 'z', depending on the radix. If {@code radix} is not in the interval
      * defined by {@code Character.MIN_RADIX} and {@code Character.MAX_RADIX}
      * then 10 is used as the base for the conversion.
+     * 
+     * <p>This method treats its argument as signed. If you want to convert an
+     * unsigned value to one of the common non-decimal bases, you may find
+     * {@link #toBinaryString}, {@code #toHexString}, or {@link #toOctalString}
+     * more convenient.
      *
      * @param v
-     *            the long to convert.
+     *            the signed long to convert.
      * @param radix
      *            the base to use for the conversion.
      * @return the string representation of {@code v}.
diff --git a/luni/src/main/java/java/lang/String.java b/luni/src/main/java/java/lang/String.java
index 1556389..8e4c9a8 100644
--- a/luni/src/main/java/java/lang/String.java
+++ b/luni/src/main/java/java/lang/String.java
@@ -2192,8 +2192,16 @@
     }
 
     /**
-     * Returns a formatted string, using the supplied format and arguments,
-     * using the default locale.
+     * Returns a localized formatted string, using the supplied format and arguments,
+     * using the user's default locale.
+     * 
+     * <p>Note that this method can be dangerous: the user's default locale may
+     * not be the locale you tested in, and this may have unexpected effects on
+     * the output. In particular, floating point numbers may be output with
+     * ',' instead of '.' as the decimal separator if that's what the user's
+     * locale dictates. If you're formatting a string other than for human
+     * consumption, you should use {@link #format(Locale,String,Object...}) and
+     * supply {@code Locale.US}.
      * 
      * @param format
      *            a format string.
diff --git a/luni/src/main/java/java/lang/StringBuffer.java b/luni/src/main/java/java/lang/StringBuffer.java
index 3ec43dc..766b942 100644
--- a/luni/src/main/java/java/lang/StringBuffer.java
+++ b/luni/src/main/java/java/lang/StringBuffer.java
@@ -24,21 +24,22 @@
 import java.io.Serializable;
 
 /**
- * StringBuffer is a variable size contiguous indexable array of characters. The
- * length of the StringBuffer is the number of characters it contains. The
- * capacity of the StringBuffer is the number of characters it can hold.
- * <p>
- * Characters may be inserted at any position up to the length of the
- * StringBuffer, increasing the length of the StringBuffer. Characters at any
- * position in the StringBuffer may be replaced, which does not affect the
- * StringBuffer length.
- * <p>
- * The capacity of a StringBuffer may be specified when the StringBuffer is
- * created. If the capacity of the StringBuffer is exceeded, the capacity is
- * increased.
+ * A modifiable {@link CharSequence sequence of characters} for use in creating
+ * strings, where all accesses are synchronized. This class has mostly been replaced
+ * by {@link StringBuilder} because this synchronization is rarely useful. This
+ * class is mainly used to interact with legacy APIs that expose it.
  * 
- * @see String
+ * <p>For particularly complex string-building needs, consider {@link java.util.Formatter}.
+ * 
+ * <p>The majority of the modification methods on this class return {@code
+ * this} so that method calls can be chained together. For example:
+ * {@code new StringBuffer("a").append("b").append("c").toString()}.
+ * 
+ * @see CharSequence
+ * @see Appendable
  * @see StringBuilder
+ * @see String
+ * @see String.format
  * @since 1.0
  */
 public final class StringBuffer extends AbstractStringBuilder implements
diff --git a/luni/src/main/java/java/lang/StringBuilder.java b/luni/src/main/java/java/lang/StringBuilder.java
index 12d401f..775864e 100644
--- a/luni/src/main/java/java/lang/StringBuilder.java
+++ b/luni/src/main/java/java/lang/StringBuilder.java
@@ -24,20 +24,21 @@
 
 /**
  * A modifiable {@link CharSequence sequence of characters} for use in creating
- * and modifying Strings. This class is intended as a direct replacement of
+ * strings. This class is intended as a direct replacement of
  * {@link StringBuffer} for non-concurrent use; unlike {@code StringBuffer} this
- * class is not synchronized for thread safety.
- * <p>
- * The majority of the modification methods on this class return {@code
- * StringBuilder}, so that, like {@code StringBuffer}s, they can be used in
- * chaining method calls together. For example, {@code new StringBuilder("One
- * should ").append("always strive ").append("to achieve Harmony")}.
+ * class is not synchronized.
+ * 
+ * <p>For particularly complex string-building needs, consider {@link java.util.Formatter}.
+ * 
+ * <p>The majority of the modification methods on this class return {@code
+ * this} so that method calls can be chained together. For example:
+ * {@code new StringBuilder("a").append("b").append("c").toString()}.
  * 
  * @see CharSequence
  * @see Appendable
  * @see StringBuffer
  * @see String
- * 
+ * @see String.format
  * @since 1.5
  */
 public final class StringBuilder extends AbstractStringBuilder implements
diff --git a/luni/src/main/java/java/util/ArrayList.java b/luni/src/main/java/java/util/ArrayList.java
index 7c46e89..ba96593 100644
--- a/luni/src/main/java/java/util/ArrayList.java
+++ b/luni/src/main/java/java/util/ArrayList.java
@@ -29,10 +29,18 @@
 import java.lang.reflect.Array;
 
 /**
- * ArrayList is an implementation of {@link List}, backed by an array. All
- * optional operations adding, removing, and replacing are supported. The
- * elements can be any objects.
- *
+ * ArrayList is an implementation of {@link List}, backed by an array.
+ * All optional operations including adding, removing, and replacing elements are supported.
+ * 
+ * <p>All elements are permitted, including null.
+ * 
+ * <p>This class is a good choice as your default {@code List} implementation.
+ * {@link Vector} synchronizes all operations, but not necessarily in a way that's
+ * meaningful to your application: synchronizing each call to {@code get}, for example, is not
+ * equivalent to synchronizing the list and iterating over it (which is probably what you intended).
+ * {@link java.util.concurrent.CopyOnWriteArrayList} is intended for the special case of very high
+ * concurrency, frequent traversals, and very rare mutations.
+ * 
  * @param <E> The element type of this list.
  * @since 1.2
  */
diff --git a/luni/src/main/java/java/util/Enumeration.java b/luni/src/main/java/java/util/Enumeration.java
index 8b8f7bd..5944a75 100644
--- a/luni/src/main/java/java/util/Enumeration.java
+++ b/luni/src/main/java/java/util/Enumeration.java
@@ -18,15 +18,19 @@
 package java.util;
 
 /**
- * An Enumeration is used to sequence over a collection of objects.
- * <p>
- * Preferably an {@link Iterator} should be used. {@code Iterator} replaces the
+ * A legacy iteration interface.
+ * 
+ * <p>New code should use {@link Iterator} instead. {@code Iterator} replaces the
  * enumeration interface and adds a way to remove elements from a collection.
- *
- * @see Hashtable
- * @see Properties
- * @see Vector
+ * 
+ * <p>If you <i>have</i> an {@code Enumeration} and want a {@code Collection}, you
+ * can use {@link Collections#list} to get a {@code List}.
+ * 
+ * <p>If you <i>need</i> an {@code Enumeration} for a legacy API and have a
+ * {@code Collection}, you can use {@link Collections#enumeration}.
+ * 
  * @version 1.0
+ * @see Iterator
  */
 public interface Enumeration<E> {
 
diff --git a/luni/src/main/java/java/util/HashMap.java b/luni/src/main/java/java/util/HashMap.java
index f79601f..19aa2b8 100644
--- a/luni/src/main/java/java/util/HashMap.java
+++ b/luni/src/main/java/java/util/HashMap.java
@@ -29,14 +29,31 @@
 import java.io.Serializable;
 
 /**
- * HashMap is an implementation of Map. All optional operations (adding and
- * removing) are supported. Keys and values can be any objects.
- *
+ * HashMap is an implementation of {@link Map}. All optional operations are supported.
+ * 
+ * <p>All elements are permitted as keys or values, including null.
+ * 
+ * <p>Note that the iteration order for HashMap is non-deterministic. If you want
+ * deterministic iteration, use {@link LinkedHashMap}.
+ * 
+ * <p>Note: the implementation of {@code HashMap} is not synchronized.
+ * If one thread of several threads accessing an instance modifies the map
+ * structurally, access to the map needs to be synchronized. A structural
+ * modification is an operation that adds or removes an entry. Changes in
+ * the value of an entry are not structural changes.
+ * 
+ * <p>The {@code Iterator} created by calling the {@code iterator} method
+ * may throw a {@code ConcurrentModificationException} if the map is structurally
+ * changed while an iterator is used to iterate over the elements. Only the
+ * {@code remove} method that is provided by the iterator allows for removal of
+ * elements during iteration. It is not possible to guarantee that this
+ * mechanism works in all cases of unsynchronized concurrent modification. It
+ * should only be used for debugging purposes.
+ * 
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
  */
-public class HashMap<K, V> extends AbstractMap<K, V>
-        implements Cloneable, Serializable {
+public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable {
     /**
      * Min capacity (other than zero) for a HashMap. Must be a power of two
      * greater than 1 (and less than 1 << 30).
@@ -60,7 +77,7 @@
     /**
      * The default load factor. Note that this implementation ignores the
      * load factor, but cannot do away with it entirely because it's
-     * metioned in the API.
+     * mentioned in the API.
      *
      * <p>Note that this constant has no impact on the behavior of the program,
      * but it is emitted as part of the serialized form. The load factor of
@@ -165,7 +182,7 @@
 
         /*
          * Note that this implementation ignores loadFactor; it always uses
-         * a load facator of 3/4. This simplifies the code and generally
+         * a load factor of 3/4. This simplifies the code and generally
          * improves performance.
          */
     }
@@ -184,7 +201,7 @@
 
     /**
      * Inserts all of the elements of map into this HashMap in a manner
-     * suitable for use by constructors and pseudocostructors (i.e., clone,
+     * suitable for use by constructors and pseudo-constructors (i.e., clone,
      * readObject). Also used by LinkedHashMap.
      */
     final void constructorPutAll(Map<? extends K, ? extends V> map) {
@@ -239,7 +256,7 @@
     /**
      * This method is called from the pseudo-constructors (clone and readObject)
      * prior to invoking constructorPut/constructorPutAll, which invoke the
-     * overriden constructorNewEntry method. Normally it is a VERY bad idea to
+     * overridden constructorNewEntry method. Normally it is a VERY bad idea to
      * invoke an overridden method from a pseudo-constructor (Effective Java
      * Item 17). In this cases it is unavoidable, and the init method provides a
      * workaround.
@@ -411,7 +428,7 @@
     }
 
     /**
-     * Give LinkedHashMap a chance to take action when we modify an exisitng
+     * Give LinkedHashMap a chance to take action when we modify an existing
      * entry.
      *
      * @param e the entry we're about to modify.
@@ -879,7 +896,7 @@
         return o1 == o2 || (o1 != null && o1.equals(o2));
     }
 
-    // Subclass (LinkedHashMap) overrrides these for correct iteration order
+    // Subclass (LinkedHashMap) overrides these for correct iteration order
     Iterator<K> newKeyIterator() { return new KeyIterator();   }
     Iterator<V> newValueIterator() { return new ValueIterator(); }
     Iterator<Entry<K, V>> newEntryIterator() { return new EntryIterator(); }
diff --git a/luni/src/main/java/java/util/Hashtable.java b/luni/src/main/java/java/util/Hashtable.java
index ead0db3..af0f4b3 100644
--- a/luni/src/main/java/java/util/Hashtable.java
+++ b/luni/src/main/java/java/util/Hashtable.java
@@ -29,22 +29,15 @@
 import java.io.Serializable;
 
 /**
- * Hashtable associates keys with values. Both keys and values cannot be null.
- * The size of the Hashtable is the number of key/value pairs it contains. The
- * capacity is the number of key/value pairs the Hashtable can hold. The load
- * factor is a float value which determines how full the Hashtable gets before
- * expanding the capacity. If the load factor of the Hashtable is exceeded, the
- * capacity is doubled.
- *
+ * Hashtable is a synchronized implementation of {@link Map}. All optional operations are supported.
+ * 
+ * <p>Neither keys nor values can be null. (Use {@code HashMap} or {@code LinkedHashMap} if you
+ * need null keys or values.)
+ * 
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
- *
- * @see Enumeration
- * @see java.io.Serializable
- * @see java.lang.Object#equals
- * @see java.lang.Object#hashCode
+ * @see HashMap
  */
-
 public class Hashtable<K, V> extends Dictionary<K, V>
         implements Map<K, V>, Cloneable, Serializable {
     /**
@@ -70,7 +63,7 @@
     /**
      * The default load factor. Note that this implementation ignores the
      * load factor, but cannot do away with it entirely because it's
-     * metioned in the API.
+     * mentioned in the API.
      *
      * <p>Note that this constant has no impact on the behavior of the program,
      * but it is emitted as part of the serialized form. The load factor of
@@ -166,7 +159,7 @@
 
         /*
          * Note that this implementation ignores loadFactor; it always uses
-         * a load facator of 3/4. This simplifies the code and generally
+         * a load factor of 3/4. This simplifies the code and generally
          * improves performance.
          */
     }
@@ -185,7 +178,7 @@
 
     /**
      * Inserts all of the elements of map into this Hashtable in a manner
-     * suitable for use by constructors and pseudocostructors (i.e., clone,
+     * suitable for use by constructors and pseudo-constructors (i.e., clone,
      * readObject).
      */
     private void constructorPutAll(Map<? extends K, ? extends V> map) {
@@ -665,7 +658,7 @@
     /**
      * Note: technically the methods of this class should synchronize the
      * backing map.  However, this would require them to have a reference
-     * to it, which would cause consiserable bloat.  Moreover, the RI
+     * to it, which would cause considerable bloat.  Moreover, the RI
      * behaves the same way.
      */
     private static class HashtableEntry<K, V> implements Entry<K, V> {
diff --git a/luni/src/main/java/java/util/Iterator.java b/luni/src/main/java/java/util/Iterator.java
index 6ebae04..bec797b 100644
--- a/luni/src/main/java/java/util/Iterator.java
+++ b/luni/src/main/java/java/util/Iterator.java
@@ -18,31 +18,29 @@
 package java.util;
 
 /**
- * An {@code Iterator} is used to sequence over a collection of objects.
- * Conceptually, an iterator is always positioned between two elements of a
- * collection. A fresh iterator is always positioned in front of the first
- * element.
+ * An iterator over a sequence of objects, such as a collection.
  * 
- * If a collection has been changed since its creation, methods {@code next} and
- * {@code hasNext()} may throw a {@code ConcurrentModificationException}.
- * Iterators with this behavior are called fail-fast iterators.
+ * <p>If a collection has been changed since the iterator was created,
+ * methods {@code next} and {@code hasNext()} may throw a {@code ConcurrentModificationException}.
+ * It is not possible to guarantee that this mechanism works in all cases of unsynchronized
+ * concurrent modification. It should only be used for debugging purposes. Iterators with this
+ * behavior are called fail-fast iterators.
+ * 
+ * <p>Implementing {@link Iterable} and returning an {@code Iterator} allows your
+ * class to be used as a collection with the enhanced for loop.
  * 
  * @param <E>
  *            the type of object returned by the iterator.
  */
 public interface Iterator<E> {
     /**
-     * Returns whether there are more elements to iterate, i.e. whether the
-     * iterator is positioned in front of an element.
-     * 
-     * @return {@code true} if there are more elements, {@code false} otherwise.
+     * Returns true if there is at least one more element, false otherwise.
      * @see #next
      */
     public boolean hasNext();
 
     /**
-     * Returns the next object in the iteration, i.e. returns the element in
-     * front of the iterator and advances the iterator by one position.
+     * Returns the next object and advances the iterator.
      * 
      * @return the next object.
      * @throws NoSuchElementException
@@ -53,7 +51,7 @@
 
     /**
      * Removes the last object returned by {@code next} from the collection.
-     * This method can only be called once after {@code next} was called.
+     * This method can only be called once between each call to {@code next}.
      * 
      * @throws UnsupportedOperationException
      *             if removing is not supported by the collection being
diff --git a/luni/src/main/java/java/util/LinkedHashMap.java b/luni/src/main/java/java/util/LinkedHashMap.java
index cd6825b..eeee1a9 100644
--- a/luni/src/main/java/java/util/LinkedHashMap.java
+++ b/luni/src/main/java/java/util/LinkedHashMap.java
@@ -22,28 +22,28 @@
 package java.util;
 
 /**
- * LinkedHashMap is a variant of HashMap. Its entries are kept in a
- * doubly-linked list. The iteration order is, by default, the order in which
- * keys were inserted. Reinserting an already existing key doesn't change the
- * order. A key is existing if a call to {@code containsKey} would return true.
- * <p>
- * If the three argument constructor is used, and {@code order} is specified as
+ * LinkedHashMap is an implementation of {@link Map} that guarantees iteration order.
+ * All optional operations are supported.
+ * 
+ * <p>All elements are permitted as keys or values, including null.
+ * 
+ * <p>Entries are kept in a doubly-linked list. The iteration order is, by default, the
+ * order in which keys were inserted. Reinserting an already-present key doesn't change the
+ * order. If the three argument constructor is used, and {@code accessOrder} is specified as
  * {@code true}, the iteration will be in the order that entries were accessed.
- * The access order gets affected by put(), get(), putAll() operations, but not
- * by operations on the collection views.
- * <p>
- * Null elements are allowed, and all the optional map operations are supported.
- * <p>
- * <b>Note:</b> The implementation of {@code LinkedHashMap} is not synchronized.
+ * The access order is affected by {@code put}, {@code get}, and {@code putAll} operations,
+ * but not by operations on the collection views.
+ * 
+ * <p>Note: the implementation of {@code LinkedHashMap} is not synchronized.
  * If one thread of several threads accessing an instance modifies the map
  * structurally, access to the map needs to be synchronized. For
  * insertion-ordered instances a structural modification is an operation that
  * removes or adds an entry. Access-ordered instances also are structurally
- * modified by put(), get() and putAll() since these methods change the order of
- * the entries. Changes in the value of an entry are not structural changes.
- * <p>
- * The Iterator that can be created by calling the {@code iterator} method
- * throws a {@code ConcurrentModificationException} if the map is structurally
+ * modified by {@code put}, {@code get}, and {@code putAll} since these methods
+ * change the order of the entries. Changes in the value of an entry are not structural changes.
+ * 
+ * <p>The {@code Iterator} created by calling the {@code iterator} method
+ * may throw a {@code ConcurrentModificationException} if the map is structurally
  * changed while an iterator is used to iterate over the elements. Only the
  * {@code remove} method that is provided by the iterator allows for removal of
  * elements during iteration. It is not possible to guarantee that this
diff --git a/luni/src/main/java/java/util/LinkedList.java b/luni/src/main/java/java/util/LinkedList.java
index 7a7e81f..9db9c9c 100644
--- a/luni/src/main/java/java/util/LinkedList.java
+++ b/luni/src/main/java/java/util/LinkedList.java
@@ -24,10 +24,16 @@
 import java.lang.reflect.Array;
 
 /**
- * LinkedList is an implementation of List, backed by a linked list. All
- * optional operations (adding, removing and replacing) are supported. The
- * elements can be any objects.
- *
+ * LinkedList is an implementation of {@link List}, backed by a doubly-linked list.
+ * All optional operations including adding, removing, and replacing elements are supported.
+ * 
+ * <p>All elements are permitted, including null.
+ * 
+ * <p>This class is primarily useful if you need queue-like behavior. It may also be useful
+ * as a list if you expect your lists to contain zero or one element, but still require the
+ * ability to scale to slightly larger numbers of elements. In general, though, you should
+ * probably use {@link ArrayList} if you don't need the queue-like behavior.
+ * 
  * @since 1.2
  */
 public class LinkedList<E> extends AbstractSequentialList<E> implements
diff --git a/luni/src/main/java/java/util/Vector.java b/luni/src/main/java/java/util/Vector.java
index 9a1b81c..8129cfe 100644
--- a/luni/src/main/java/java/util/Vector.java
+++ b/luni/src/main/java/java/util/Vector.java
@@ -23,20 +23,18 @@
 import java.lang.reflect.Array;
 
 /**
- * Vector is a variable size contiguous indexable array of objects. The size of
- * the vector is the number of objects it contains. The capacity of the vector
- * is the number of objects it can hold.
- * <p>
- * Objects may be inserted at any position up to the size of the vector, thus
- * increasing the size of the vector. Objects at any position in the vector may
- * be removed, thus shrinking the size of the Vector. Objects at any position in
- * the Vector may be replaced, which does not affect the vector's size.
- * <p>
- * The capacity of a vector may be specified when the vector is created. If the
- * capacity of the vector is exceeded, the capacity is increased (doubled by
- * default).
- *
- * @see java.lang.StringBuffer
+ * Vector is an implementation of {@link List}, backed by an array and synchronized.
+ * All optional operations including adding, removing, and replacing elements are supported.
+ * 
+ * <p>All elements are permitted, including null.
+ * 
+ * <p>This class is equivalent to {@link ArrayList} with synchronized operations. This has a
+ * performance cost, and the synchronization is not necessarily meaningful to your application:
+ * synchronizing each call to {@code get}, for example, is not equivalent to synchronizing on the
+ * list and iterating over it (which is probably what you intended). If you do need very highly
+ * concurrent access, you should also consider {@link CopyOnWriteArrayList}.
+ * 
+ * @param <E> The element type of this list.
  */
 public class Vector<E> extends AbstractList<E> implements List<E>,
         RandomAccess, Cloneable, Serializable {
diff --git a/nio/src/main/java/java/nio/DoubleBuffer.java b/nio/src/main/java/java/nio/DoubleBuffer.java
index 4e0ab01..3bea69e 100644
--- a/nio/src/main/java/java/nio/DoubleBuffer.java
+++ b/nio/src/main/java/java/nio/DoubleBuffer.java
@@ -233,12 +233,17 @@
     public abstract DoubleBuffer duplicate();
 
     /**
-     * Checks whether this double buffer is equal to another object.
-     * <p>
-     * If {@code other} is not a double buffer then {@code false} is returned.
-     * Two double buffers are equal if and only if their remaining doubles are
-     * exactly the same. Position, limit, capacity and mark are not considered.
-     *
+     * Checks whether this double buffer is equal to another object. If {@code
+     * other} is not a {@code DoubleBuffer} then {@code false} is returned.
+     * 
+     * <p>Two double buffers are equal if their remaining doubles are equal.
+     * Position, limit, capacity and mark are not considered.
+     * 
+     * <p>This method considers two doubles {@code a} and {@code b} to be equal
+     * if {@code a == b} or if {@code a} and {@code b} are both {@code NaN}.
+     * Unlike {@link Double#equals}, this method considers {@code -0.0} and
+     * {@code +0.0} to be equal.
+     * 
      * @param other
      *            the object to compare with this double buffer.
      * @return {@code true} if this double buffer is equal to {@code other},
@@ -259,7 +264,9 @@
         int otherPosition = otherBuffer.position;
         boolean equalSoFar = true;
         while (equalSoFar && (myPosition < limit)) {
-            equalSoFar = get(myPosition++) == otherBuffer.get(otherPosition++);
+            double a = get(myPosition++);
+            double b = otherBuffer.get(otherPosition++);
+            equalSoFar = a == b || (a != a && b != b);
         }
 
         return equalSoFar;
diff --git a/nio/src/main/java/java/nio/FloatBuffer.java b/nio/src/main/java/java/nio/FloatBuffer.java
index cab94c3..15239b1 100644
--- a/nio/src/main/java/java/nio/FloatBuffer.java
+++ b/nio/src/main/java/java/nio/FloatBuffer.java
@@ -233,12 +233,17 @@
     public abstract FloatBuffer duplicate();
 
     /**
-     * Checks whether this float buffer is equal to another object.
-     * <p>
-     * If {@code other} is not a float buffer then {@code false} is returned.
-     * Two float buffers are equal if and only if their remaining floats are
-     * exactly the same. Position, limit, capacity and mark are not considered.
-     *
+     * Checks whether this float buffer is equal to another object. If {@code
+     * other} is not a {@code FloatBuffer} then {@code false} is returned.
+     * 
+     * <p>Two float buffers are equal if their remaining floats are equal.
+     * Position, limit, capacity and mark are not considered.
+     * 
+     * <p>This method considers two floats {@code a} and {@code b} to be equal
+     * if {@code a == b} or if {@code a} and {@code b} are both {@code NaN}.
+     * Unlike {@link Float#equals}, this method considers {@code -0.0} and
+     * {@code +0.0} to be equal.
+     * 
      * @param other
      *            the object to compare with this float buffer.
      * @return {@code true} if this float buffer is equal to {@code other},
@@ -259,7 +264,9 @@
         int otherPosition = otherBuffer.position;
         boolean equalSoFar = true;
         while (equalSoFar && (myPosition < limit)) {
-            equalSoFar = get(myPosition++) == otherBuffer.get(otherPosition++);
+            float a = get(myPosition++);
+            float b = otherBuffer.get(otherPosition++);
+            equalSoFar = a == b || (a != a && b != b);
         }
 
         return equalSoFar;
diff --git a/security/src/main/files/certimport.sh b/security/src/main/files/certimport.sh
index c021a10..ca36a70 100755
--- a/security/src/main/files/certimport.sh
+++ b/security/src/main/files/certimport.sh
@@ -7,12 +7,40 @@
 
 CERTSTORE=cacerts.bks
 
+# put required 1.6 VM at head of PATH
+JDK6PATH=/usr/lib/jvm/java-6-sun/bin
+if [ ! -e $JDK6PATH/java ] ; then
+  set +x
+  echo
+  echo "WARNING: could not find $JDK6PATH/java but continuing anyway."
+  echo "    you might consider making sure the expected JDK is installed"
+  echo "    or updating its location in this script."
+  echo
+  set -x
+fi
+export PATH=$JDK6PATH:$PATH
+
 # Check java version.
 JAVA_VERSION=`java -version 2>&1 | head -1`
 JAVA_VERSION_MINOR=`expr match "$JAVA_VERSION" "java version \"[1-9]\.\([0-9]\).*\""`
 if [ $JAVA_VERSION_MINOR -lt 6 ]; then
-  echo "java version 1.6 or greater required for keytool usage"
-  exit 255
+  set +x
+  echo
+  echo "ERROR: java version 1.6 or greater required for keytool usage"
+  echo
+  exit 1
+fi
+
+PROVIDER_CLASS=org.bouncycastle.jce.provider.BouncyCastleProvider
+PROVIDER_PATH=/usr/share/java/bcprov.jar
+
+if [ ! -e $PROVIDER_PATH ] ; then
+  set +x
+  echo
+  echo "ERROR: could not find provider path $PROVIDER_PATH. Try installing with:"
+  echo "    sudo apt-get install libbcprov-java"
+  echo
+  exit 1
 fi
 
 if [ -a $CERTSTORE ]; then
@@ -34,8 +62,8 @@
       -file <(openssl x509 -in cacerts/$cert) \
       -keystore $CERTSTORE \
       -storetype BKS \
-      -provider org.bouncycastle.jce.provider.BouncyCastleProvider \
-      -providerpath /usr/share/java/bcprov.jar \
+      -provider $PROVIDER_CLASS \
+      -providerpath $PROVIDER_PATH \
       -storepass $STOREPASS
   let "COUNTER=$COUNTER + 1"
 done
diff --git a/sql/src/main/java/java/sql/package.html b/sql/src/main/java/java/sql/package.html
index 9ae2488..0799bb7 100644
--- a/sql/src/main/java/java/sql/package.html
+++ b/sql/src/main/java/java/sql/package.html
@@ -1,8 +1,10 @@
 <html>
-  <body>
-    <p>
-      Provides a standard interface for accessing SQL-based databases.
-    </p>
-    @since Android 1.0
-  </body>
-</html>
\ No newline at end of file
+<body>
+<p>Provides a compatibility interface for accessing SQL-based databases.
+The <code>android.database</code> and <code>android.database.sqlite</code>
+packages offer a higher-performance alternative where source compatibility
+is not an issue.</p>
+
+<p>Note that you must provide your own JDBC driver.</p>
+</body>
+</html>
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
index 4e689fb..e995174 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/AttrImpl.java
@@ -32,7 +32,7 @@
  * the DOM implementation can easily access them while maintaining the DOM tree
  * structure.
  */
-public class AttrImpl extends NodeImpl implements Attr {
+public final class AttrImpl extends NodeImpl implements Attr {
 
     // Maintained by ElementImpl.
     ElementImpl ownerElement;
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
index b1802a6..c677e58 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
@@ -17,17 +17,14 @@
 package org.apache.harmony.xml.dom;
 
 import org.w3c.dom.Attr;
-import org.w3c.dom.CDATASection;
 import org.w3c.dom.CharacterData;
 import org.w3c.dom.Comment;
 import org.w3c.dom.DOMConfiguration;
 import org.w3c.dom.DOMException;
 import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
-import org.w3c.dom.DocumentFragment;
 import org.w3c.dom.DocumentType;
 import org.w3c.dom.Element;
-import org.w3c.dom.EntityReference;
 import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -76,7 +73,7 @@
      * attach user data to the document to save those fields. Xerces also takes
      * this approach.
      */
-    private WeakHashMap<Node, Map<String, UserData>> nodeToUserData;
+    private WeakHashMap<NodeImpl, Map<String, UserData>> nodeToUserData;
 
     public DocumentImpl(DOMImplementationImpl impl, String namespaceURI,
             String qualifiedName, DocumentType doctype, String inputEncoding) {
@@ -120,147 +117,232 @@
         
         return true;
     }
-    
-    /**
-     * Clones a node and (if requested) its children. The source node(s) may
-     * have been created by a different DocumentImpl or even DOM implementation.
-     * 
-     * @param node The node to clone.
-     * @param deep If true, a deep copy is created (including all child nodes).
-     * 
-     * @return The new node.
-     */
-    Node cloneNode(Node node, boolean deep) throws DOMException {
-        Node target;
-        
-        switch (node.getNodeType()) {
-            case Node.ATTRIBUTE_NODE: {
-                Attr source = (Attr)node;
-                target = createAttributeNS(source.getNamespaceURI(), source.getLocalName());
-                target.setPrefix(source.getPrefix());
-                target.setNodeValue(source.getNodeValue());
-                break;
-            }
-            case Node.CDATA_SECTION_NODE: {
-                CharacterData source = (CharacterData)node;
-                target = createCDATASection(source.getData());
-                break;
-            }
-            case Node.COMMENT_NODE: {
-                Comment source = (Comment)node;
-                target = createComment(source.getData());
-                break;
-            }
-            case Node.DOCUMENT_FRAGMENT_NODE: {
-                // Source is irrelevant in this case.
-                target = createDocumentFragment();
-                break;
-            }
-            case Node.DOCUMENT_NODE: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a Document node");
-            }
-            case Node.DOCUMENT_TYPE_NODE: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a DocumentType node");
-            }
-            case Node.ELEMENT_NODE: {
-                Element source = (Element)node;
-                target = createElementNS(source.getNamespaceURI(), source.getLocalName());
-                target.setPrefix(source.getPrefix());
 
-                NamedNodeMap map = source.getAttributes();
-                for (int i = 0; i < map.getLength(); i++) {
-                    Attr attr = (Attr)map.item(i);
-                    ((Element)target).setAttributeNodeNS((Attr)cloneNode(attr, deep));
+    /**
+     * Returns a shallow copy of the given node. If the node is an element node,
+     * its attributes are always copied.
+     *
+     * @param node a node belonging to any document or DOM implementation.
+     * @param operation the operation type to use when notifying user data
+     *     handlers of copied element attributes. It is the caller's
+     *     responsibility to notify user data handlers of the returned node.
+     * @return a new node whose document is this document and whose DOM
+     *     implementation is this DOM implementation.
+     */
+    private NodeImpl shallowCopy(short operation, Node node) {
+        switch (node.getNodeType()) {
+            case Node.ATTRIBUTE_NODE:
+                Attr attr = (Attr) node;
+                AttrImpl attrCopy = createAttributeNS(attr.getNamespaceURI(), attr.getLocalName());
+                attrCopy.setPrefix(attr.getPrefix());
+                attrCopy.setNodeValue(attr.getNodeValue());
+                return attrCopy;
+
+            case Node.CDATA_SECTION_NODE:
+                return createCDATASection(((CharacterData) node).getData());
+
+            case Node.COMMENT_NODE:
+                return createComment(((Comment) node).getData());
+
+            case Node.DOCUMENT_FRAGMENT_NODE:
+                return createDocumentFragment();
+
+            case Node.DOCUMENT_NODE:
+            case Node.DOCUMENT_TYPE_NODE:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Cannot copy node of type " + node.getNodeType());
+
+            case Node.ELEMENT_NODE:
+                Element element = (Element) node;
+                ElementImpl elementCopy = createElementNS(
+                        element.getNamespaceURI(), element.getLocalName());
+                elementCopy.setPrefix(element.getPrefix());
+                NamedNodeMap attributes = element.getAttributes();
+                for (int i = 0; i < attributes.getLength(); i++) {
+                    Node elementAttr = attributes.item(i);
+                    AttrImpl elementAttrCopy = (AttrImpl) shallowCopy(operation, elementAttr);
+                    notifyUserDataHandlers(operation, elementAttr, elementAttrCopy);
+                    elementCopy.setAttributeNodeNS(elementAttrCopy);
                 }
-                break;
-            }
-            case Node.ENTITY_NODE: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone an Entity node");
-            }
-            case Node.ENTITY_REFERENCE_NODE: {
-                EntityReference source = (EntityReference)node;
-                target = createEntityReference(source.getNodeName());
-                break;
-            }
-            case Node.NOTATION_NODE: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone a Notation node");
-            }
-            case Node.PROCESSING_INSTRUCTION_NODE: {
-                ProcessingInstruction source = (ProcessingInstruction)node;
-                target = createProcessingInstruction(source.getTarget(), source.getData());
-                break;
-            }
-            case Node.TEXT_NODE: {
-                Text source = (Text)node;
-                target = createTextNode(source.getData());
-                break;
-            }
-            default: {
-                throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "Cannot clone unknown node type " + node.getNodeType() + " (" + node.getClass().getSimpleName() + ")");
-            }
+                return elementCopy;
+
+            case Node.ENTITY_NODE:
+            case Node.NOTATION_NODE:
+                // TODO: implement this when we support these node types
+                throw new UnsupportedOperationException();
+
+            case Node.ENTITY_REFERENCE_NODE:
+                /*
+                 * When we support entities in the doctype, this will need to
+                 * behave differently for clones vs. imports. Clones copy
+                 * entities by value, copying the referenced subtree from the
+                 * original document. Imports copy entities by reference,
+                 * possibly referring to a different subtree in the new
+                 * document.
+                 */
+                return createEntityReference(node.getNodeName());
+
+            case Node.PROCESSING_INSTRUCTION_NODE:
+                ProcessingInstruction pi = (ProcessingInstruction) node;
+                return createProcessingInstruction(pi.getTarget(), pi.getData());
+
+            case Node.TEXT_NODE:
+                return createTextNode(((Text) node).getData());
+
+            default:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Unsupported node type " + node.getNodeType());
         }
+    }
+
+    /**
+     * Returns a copy of the given node or subtree with this document as its
+     * owner.
+     *
+     * @param operation either {@link UserDataHandler#NODE_CLONED} or
+     *      {@link UserDataHandler#NODE_IMPORTED}.
+     * @param node a node belonging to any document or DOM implementation.
+     * @param deep true to recursively copy any child nodes; false to do no such
+     *      copying and return a node with no children.
+     */
+    Node cloneOrImportNode(short operation, Node node, boolean deep) {
+        NodeImpl copy = shallowCopy(operation, node);
 
         if (deep) {
             NodeList list = node.getChildNodes();
             for (int i = 0; i < list.getLength(); i++) {
-                Node child = cloneNode(list.item(i), deep);
-                target.appendChild(child);
+                copy.appendChild(cloneOrImportNode(operation, list.item(i), deep));
             }
         }
 
-        notifyUserDataHandlers(UserDataHandler.NODE_CLONED, node, target);
-
-        return target;
+        notifyUserDataHandlers(operation, node, copy);
+        return copy;
     }
 
-    public AttrImpl createAttribute(String name) throws DOMException {
+    public Node importNode(Node importedNode, boolean deep) {
+        return cloneOrImportNode(UserDataHandler.NODE_IMPORTED, importedNode, deep);
+    }
+
+    /**
+     * Detaches the node from its parent (if any) and changes its document to
+     * this document. The node's subtree and attributes will remain attached,
+     * but their document will be changed to this document.
+     */
+    public Node adoptNode(Node node) {
+        if (!(node instanceof NodeImpl)) {
+            return null; // the API specifies this quiet failure
+        }
+        NodeImpl nodeImpl = (NodeImpl) node;
+        switch (nodeImpl.getNodeType()) {
+            case Node.ATTRIBUTE_NODE:
+                AttrImpl attr = (AttrImpl) node;
+                if (attr.ownerElement != null) {
+                    attr.ownerElement.removeAttributeNode(attr);
+                }
+                break;
+
+            case Node.DOCUMENT_FRAGMENT_NODE:
+            case Node.ENTITY_REFERENCE_NODE:
+            case Node.PROCESSING_INSTRUCTION_NODE:
+            case Node.TEXT_NODE:
+            case Node.CDATA_SECTION_NODE:
+            case Node.COMMENT_NODE:
+            case Node.ELEMENT_NODE:
+                break;
+
+            case Node.DOCUMENT_NODE:
+            case Node.DOCUMENT_TYPE_NODE:
+            case Node.ENTITY_NODE:
+            case Node.NOTATION_NODE:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Cannot adopt nodes of type " + nodeImpl.getNodeType());
+
+            default:
+                throw new DOMException(DOMException.NOT_SUPPORTED_ERR,
+                        "Unsupported node type " + node.getNodeType());
+        }
+
+        Node parent = nodeImpl.getParentNode();
+        if (parent != null) {
+            parent.removeChild(nodeImpl);
+        }
+
+        changeDocumentToThis(nodeImpl);
+        notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, node, null);
+        return nodeImpl;
+    }
+
+    /**
+     * Recursively change the document of {@code node} without also changing its
+     * parent node. Only adoptNode() should invoke this method, otherwise nodes
+     * will be left in an inconsistent state.
+     */
+    private void changeDocumentToThis(NodeImpl node) {
+        Map<String, UserData> userData = node.document.getUserDataMapForRead(node);
+        if (!userData.isEmpty()) {
+            getUserDataMap(node).putAll(userData);
+        }
+        node.document = this;
+
+        // change the document on all child nodes
+        NodeList list = node.getChildNodes();
+        for (int i = 0; i < list.getLength(); i++) {
+            changeDocumentToThis((NodeImpl) list.item(i));
+        }
+
+        // change the document on all attribute nodes
+        if (node.getNodeType() == Node.ELEMENT_NODE) {
+            NamedNodeMap attributes = node.getAttributes();
+            for (int i = 0; i < attributes.getLength(); i++) {
+                changeDocumentToThis((AttrImpl) attributes.item(i));
+            }
+        }
+    }
+
+    public AttrImpl createAttribute(String name) {
         return new AttrImpl(this, name);
     }
 
-    public Attr createAttributeNS(String namespaceURI, String qualifiedName)
-            throws DOMException {
+    public AttrImpl createAttributeNS(String namespaceURI, String qualifiedName) {
         return new AttrImpl(this, namespaceURI, qualifiedName);
     }
 
-    public CDATASection createCDATASection(String data) throws DOMException {
+    public CDATASectionImpl createCDATASection(String data) {
         return new CDATASectionImpl(this, data);
     }
 
-    public Comment createComment(String data) {
+    public CommentImpl createComment(String data) {
         return new CommentImpl(this, data);
     }
 
-    public DocumentFragment createDocumentFragment() {
+    public DocumentFragmentImpl createDocumentFragment() {
         return new DocumentFragmentImpl(this);
     }
 
-    public Element createElement(String tagName) throws DOMException {
+    public ElementImpl createElement(String tagName) {
         return new ElementImpl(this, tagName);
     }
 
-    public Element createElementNS(String namespaceURI, String qualifiedName)
-            throws DOMException {
+    public ElementImpl createElementNS(String namespaceURI, String qualifiedName) {
         return new ElementImpl(this, namespaceURI, qualifiedName);
     }
 
-    public EntityReference createEntityReference(String name)
-            throws DOMException {
+    public EntityReferenceImpl createEntityReference(String name) {
         return new EntityReferenceImpl(this, name);
     }
 
-    public ProcessingInstruction createProcessingInstruction(String target,
-            String data) throws DOMException {
+    public ProcessingInstructionImpl createProcessingInstruction(String target, String data) {
         return new ProcessingInstructionImpl(this, target, data);
     }
 
-    public Text createTextNode(String data) {
+    public TextImpl createTextNode(String data) {
         return new TextImpl(this, data);
     }
 
     public DocumentType getDoctype() {
-        for (int i = 0; i < children.size(); i++) {
-            if (children.get(i) instanceof DocumentType) {
-                return (DocumentType) children.get(i);
+        for (LeafNodeImpl child : children) {
+            if (child instanceof DocumentType) {
+                return (DocumentType) child;
             }
         }
 
@@ -268,9 +350,9 @@
     }
 
     public Element getDocumentElement() {
-        for (int i = 0; i < children.size(); i++) {
-            if (children.get(i) instanceof Element) {
-                return (Element) children.get(i);
+        for (LeafNodeImpl child : children) {
+            if (child instanceof Element) {
+                return (Element) child;
             }
         }
 
@@ -311,13 +393,8 @@
         return Node.DOCUMENT_NODE;
     }
 
-    public Node importNode(Node importedNode, boolean deep) throws DOMException {
-        // TODO: callback the UserDataHandler with a NODE_IMPORTED event
-        return cloneNode(importedNode, deep);
-    }
-
     @Override
-    public Node insertChildAt(Node newChild, int index) throws DOMException {
+    public Node insertChildAt(Node newChild, int index) {
         // Make sure we have at most one root element and one DTD element.
         if (newChild instanceof Element && getDocumentElement() != null) {
             throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR,
@@ -330,7 +407,7 @@
         return super.insertChildAt(newChild, index);
     }
 
-    @Override public String getTextContent() throws DOMException {
+    @Override public String getTextContent() {
         return null;
     }
 
@@ -346,7 +423,7 @@
         return xmlStandalone;
     }
 
-    public void setXmlStandalone(boolean xmlStandalone) throws DOMException {
+    public void setXmlStandalone(boolean xmlStandalone) {
         this.xmlStandalone = xmlStandalone;
     }
 
@@ -354,7 +431,7 @@
         return xmlVersion;
     }
 
-    public void setXmlVersion(String xmlVersion) throws DOMException {
+    public void setXmlVersion(String xmlVersion) {
         this.xmlVersion = xmlVersion;
     }
 
@@ -374,11 +451,6 @@
         this.documentUri = documentUri;
     }
 
-    public Node adoptNode(Node source) throws DOMException {
-        // TODO: callback the UserDataHandler with a NODE_ADOPTED event
-        throw new UnsupportedOperationException(); // TODO
-    }
-
     public DOMConfiguration getDomConfig() {
         if (domConfiguration == null) {
             domConfiguration = new DOMConfigurationImpl();
@@ -395,8 +467,7 @@
         ((DOMConfigurationImpl) getDomConfig()).normalize(root);
     }
 
-    public Node renameNode(Node n, String namespaceURI, String qualifiedName)
-            throws DOMException {
+    public Node renameNode(Node n, String namespaceURI, String qualifiedName) {
         // TODO: callback the UserDataHandler with a NODE_RENAMED event
         throw new UnsupportedOperationException(); // TODO
     }
@@ -405,9 +476,9 @@
      * Returns a map with the user data objects attached to the specified node.
      * This map is readable and writable.
      */
-    Map<String, UserData> getUserDataMap(Node node) {
+    Map<String, UserData> getUserDataMap(NodeImpl node) {
         if (nodeToUserData == null) {
-            nodeToUserData = new WeakHashMap<Node, Map<String, UserData>>();
+            nodeToUserData = new WeakHashMap<NodeImpl, Map<String, UserData>>();
         }
         Map<String, UserData> userDataMap = nodeToUserData.get(node);
         if (userDataMap == null) {
@@ -421,7 +492,7 @@
      * Returns a map with the user data objects attached to the specified node.
      * The returned map may be read-only.
      */
-    Map<String, UserData> getUserDataMapForRead(Node node) {
+    Map<String, UserData> getUserDataMapForRead(NodeImpl node) {
         if (nodeToUserData == null) {
             return Collections.emptyMap();
         }
@@ -434,13 +505,28 @@
     /**
      * Calls {@link UserDataHandler#handle} on each of the source node's
      * value/handler pairs.
+     *
+     * <p>If the source node comes from another DOM implementation, user data
+     * handlers will <strong>not</strong> be notified. The DOM API provides no
+     * mechanism to inspect a foreign node's user data.
      */
-    private void notifyUserDataHandlers(short operation, Node src, Node dst) {
-        for (Map.Entry<String, UserData> entry : getUserDataMapForRead(src).entrySet()) {
+    private static void notifyUserDataHandlers(
+            short operation, Node source, NodeImpl destination) {
+        if (!(source instanceof NodeImpl)) {
+            return;
+        }
+
+        NodeImpl srcImpl = (NodeImpl) source;
+        if (srcImpl.document == null) {
+            return;
+        }
+
+        for (Map.Entry<String, UserData> entry
+                : srcImpl.document.getUserDataMapForRead(srcImpl).entrySet()) {
             UserData userData = entry.getValue();
             if (userData.handler != null) {
                 userData.handler.handle(
-                        operation, entry.getKey(), userData.value, src, dst);
+                        operation, entry.getKey(), userData.value, source, destination);
             }
         }
     }
diff --git a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
index 8376689..5940417 100644
--- a/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
+++ b/xml/src/main/java/org/apache/harmony/xml/dom/NodeImpl.java
@@ -56,8 +56,8 @@
         throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, null);
     }
 
-    public Node cloneNode(boolean deep) {
-        return document.cloneNode(this, deep);
+    public final Node cloneNode(boolean deep) {
+        return document.cloneOrImportNode(UserDataHandler.NODE_CLONED, this, deep);
     }
 
     public NamedNodeMap getAttributes() {
diff --git a/xml/src/test/java/tests/xml/DomTest.java b/xml/src/test/java/tests/xml/DomTest.java
index 0bb27dc..a5fdbd8 100644
--- a/xml/src/test/java/tests/xml/DomTest.java
+++ b/xml/src/test/java/tests/xml/DomTest.java
@@ -16,6 +16,7 @@
 
 package tests.xml;
 
+import junit.framework.AssertionFailedError;
 import junit.framework.TestCase;
 import org.w3c.dom.Attr;
 import org.w3c.dom.CDATASection;
@@ -27,7 +28,9 @@
 import org.w3c.dom.Element;
 import org.w3c.dom.Entity;
 import org.w3c.dom.EntityReference;
+import org.w3c.dom.NamedNodeMap;
 import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
 import org.w3c.dom.Notation;
 import org.w3c.dom.ProcessingInstruction;
 import org.w3c.dom.Text;
@@ -36,6 +39,7 @@
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
@@ -48,8 +52,12 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
+import static org.w3c.dom.UserDataHandler.NODE_ADOPTED;
 import static org.w3c.dom.UserDataHandler.NODE_CLONED;
+import static org.w3c.dom.UserDataHandler.NODE_IMPORTED;
 
 /**
  * Construct a DOM and then interrogate it.
@@ -111,6 +119,7 @@
 
     @Override protected void setUp() throws Exception {
         transformer = TransformerFactory.newInstance().newTransformer();
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         factory.setNamespaceAware(true);
         builder = factory.newDocumentBuilder();
@@ -817,6 +826,186 @@
         assertEquals(expected, handler.calls);
     }
 
+    /**
+     * A shallow import requires importing the attributes but not the child
+     * nodes.
+     */
+    public void testUserDataHandlerNotifiedOfShallowImports() {
+        RecordingHandler handler = new RecordingHandler();
+        name.setUserData("a", "apple", handler);
+        name.setUserData("b", "banana", handler);
+        standard.setUserData("c", "cat", handler);
+        waffles.setUserData("d", "dog", handler);
+
+        Document newDocument = builder.newDocument();
+        Element importedName = (Element) newDocument.importNode(name, false);
+        Attr importedStandard = importedName.getAttributeNode("a:standard");
+
+        Set<String> expected = new HashSet<String>();
+        expected.add(notification(NODE_IMPORTED, "a", "apple", name, importedName));
+        expected.add(notification(NODE_IMPORTED, "b", "banana", name, importedName));
+        expected.add(notification(NODE_IMPORTED, "c", "cat", standard, importedStandard));
+        assertEquals(expected, handler.calls);
+    }
+
+    /**
+     * A deep import requires cloning both the attributes and the child nodes.
+     */
+    public void testUserDataHandlerNotifiedOfDeepImports() {
+        RecordingHandler handler = new RecordingHandler();
+        name.setUserData("a", "apple", handler);
+        name.setUserData("b", "banana", handler);
+        standard.setUserData("c", "cat", handler);
+        waffles.setUserData("d", "dog", handler);
+
+        Document newDocument = builder.newDocument();
+        Element importedName = (Element) newDocument.importNode(name, true);
+        Attr importedStandard = importedName.getAttributeNode("a:standard");
+        Text importedWaffles = (Text) importedName.getChildNodes().item(0);
+
+        Set<String> expected = new HashSet<String>();
+        expected.add(notification(NODE_IMPORTED, "a", "apple", name, importedName));
+        expected.add(notification(NODE_IMPORTED, "b", "banana", name, importedName));
+        expected.add(notification(NODE_IMPORTED, "c", "cat", standard, importedStandard));
+        expected.add(notification(NODE_IMPORTED, "d", "dog", waffles, importedWaffles));
+        assertEquals(expected, handler.calls);
+    }
+
+    public void testImportNodeDeep() throws TransformerException {
+        String original = domToStringStripElementWhitespace(document);
+
+        Document newDocument = builder.newDocument();
+        Element importedItem = (Element) newDocument.importNode(item, true);
+        assertDetached(item.getParentNode(), importedItem);
+
+        newDocument.appendChild(importedItem);
+        String expected = original.replaceAll("</?menu>", "");
+        assertEquals(expected, domToStringStripElementWhitespace(newDocument));
+    }
+
+    public void testImportNodeShallow() throws TransformerException {
+        Document newDocument = builder.newDocument();
+        Element importedItem = (Element) newDocument.importNode(item, false);
+        assertDetached(item.getParentNode(), importedItem);
+
+        newDocument.appendChild(importedItem);
+        assertEquals("<item xmlns=\"http://food\" xmlns:a=\"http://addons\"/>",
+                domToString(newDocument));
+    }
+
+    public void testNodeAdoption() throws Exception {
+        for (Node node : allNodes) {
+            if (node == document || node == doctype || node == sp || node == png) {
+                assertNotAdoptable(node);
+            } else {
+                adoptAndCheck(node);
+            }
+        }
+    }
+
+    private void assertNotAdoptable(Node node) {
+        try {
+            builder.newDocument().adoptNode(node);
+            fail();
+        } catch (DOMException e) {
+        }
+    }
+
+    /**
+     * Adopts the node into another document, then adopts the root element, and
+     * then attaches the adopted node in the proper place. The net result should
+     * be that the document's entire contents have moved to another document.
+     */
+    private void adoptAndCheck(Node node) throws Exception {
+        String original = domToString(document);
+        Document newDocument = builder.newDocument();
+
+        // remember where to insert the node in the new document
+        boolean isAttribute = node.getNodeType() == Node.ATTRIBUTE_NODE;
+        Node parent = isAttribute
+                ? ((Attr) node).getOwnerElement() : node.getParentNode();
+        Node nextSibling = node.getNextSibling();
+
+        // move the node and make sure it was detached
+        assertSame(node, newDocument.adoptNode(node));
+        assertDetached(parent, node);
+
+        // move the rest of the document and wire the adopted back into place
+        assertSame(menu, newDocument.adoptNode(menu));
+        newDocument.appendChild(menu);
+        if (isAttribute) {
+            ((Element) parent).setAttributeNodeNS((Attr) node);
+        } else if (nextSibling != null) {
+            parent.insertBefore(node, nextSibling);
+        } else if (parent != document) {
+            parent.appendChild(node);
+        }
+
+        assertEquals(original, domToString(newDocument));
+        document = newDocument;
+    }
+
+    private void assertDetached(Node formerParent, Node node) {
+        assertNull(node.getParentNode());
+        NodeList children = formerParent.getChildNodes();
+        for (int i = 0; i < children.getLength(); i++) {
+            assertTrue(children.item(i) != node);
+        }
+        if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
+            assertNull(((Attr) node).getOwnerElement());
+            NamedNodeMap attributes = formerParent.getAttributes();
+            for (int i = 0; i < attributes.getLength(); i++) {
+                assertTrue(attributes.item(i) != node);
+            }
+        }
+    }
+
+    public void testAdoptionImmediatelyAfterParsing() throws Exception {
+        Document newDocument = builder.newDocument();
+        try {
+            assertSame(name, newDocument.adoptNode(name));
+            assertSame(newDocument, name.getOwnerDocument());
+            assertSame(newDocument, standard.getOwnerDocument());
+            assertSame(newDocument, waffles.getOwnerDocument());
+        } catch (Throwable e) {
+            AssertionFailedError failure = new AssertionFailedError(
+                    "This implementation fails to adopt nodes before the "
+                            + "document has been traversed");
+            failure.initCause(e);
+            throw failure;
+        }
+    }
+
+    /**
+     * There should be notifications for adopted node itself but none of its
+     * children. The DOM spec is vague on this, so we're consistent with the RI.
+     */
+    public void testUserDataHandlerNotifiedOfOnlyShallowAdoptions() throws Exception {
+        /*
+         * Force a traversal of the document, otherwise this test may fail for
+         * an unrelated reason on version 5 of the RI. That behavior is
+         * exercised by testAdoptionImmediatelyAfterParsing().
+         */
+        domToString(document);
+
+        RecordingHandler handler = new RecordingHandler();
+        name.setUserData("a", "apple", handler);
+        name.setUserData("b", "banana", handler);
+        standard.setUserData("c", "cat", handler);
+        waffles.setUserData("d", "dog", handler);
+
+        Document newDocument = builder.newDocument();
+        assertSame(name, newDocument.adoptNode(name));
+        assertSame(newDocument, name.getOwnerDocument());
+        assertSame(newDocument, standard.getOwnerDocument());
+        assertSame(newDocument, waffles.getOwnerDocument());
+
+        Set<String> expected = new HashSet<String>();
+        expected.add(notification(NODE_ADOPTED, "a", "apple", name, null));
+        expected.add(notification(NODE_ADOPTED, "b", "banana", name, null));
+        assertEquals(expected, handler.calls);
+    }
+
     private class RecordingHandler implements UserDataHandler {
         final Set<String> calls = new HashSet<String>();
         public void handle(short operation, String key, Object data, Node src, Node dst) {
@@ -831,6 +1020,29 @@
     private String domToString(Document document) throws TransformerException {
         StringWriter writer = new StringWriter();
         transformer.transform(new DOMSource(document), new StreamResult(writer));
-        return writer.toString();
+        String result = writer.toString();
+
+        /*
+         * Hack: swap <name>'s a:standard attribute and deluxe attribute if
+         * they're out of order. Some document transformations reorder the
+         * attributes, which causes pain when we try to use String comparison on
+         * them.
+         */
+        Matcher attributeMatcher = Pattern.compile(" a:standard=\"[^\"]+\"").matcher(result);
+        if (attributeMatcher.find()) {
+            result = result.substring(0, attributeMatcher.start())
+                    + result.substring(attributeMatcher.end());
+            int insertionPoint = result.indexOf(" deluxe=\"");
+            result = result.substring(0, insertionPoint)
+                    + attributeMatcher.group()
+                    + result.substring(insertionPoint);
+        }
+
+        return result;
+    }
+
+    private String domToStringStripElementWhitespace(Document document)
+            throws TransformerException {
+        return domToString(document).replaceAll("(?m)>\\s+<", "><");
     }
 }
diff --git a/xml/src/test/java/tests/xml/NormalizeTest.java b/xml/src/test/java/tests/xml/NormalizeTest.java
index 6fa6c97..f35ca10 100644
--- a/xml/src/test/java/tests/xml/NormalizeTest.java
+++ b/xml/src/test/java/tests/xml/NormalizeTest.java
@@ -32,6 +32,8 @@
 import org.xml.sax.InputSource;
 
 import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
@@ -588,10 +590,10 @@
 
     private String domToString(Document document) throws TransformerException {
         StringWriter writer = new StringWriter();
-        TransformerFactory.newInstance().newTransformer()
-                .transform(new DOMSource(document), new StreamResult(writer));
-        String xml = writer.toString();
-        return xml.replaceFirst("<\\?xml[^?]*\\?>", "");
+        Transformer transformer = TransformerFactory.newInstance() .newTransformer();
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+        transformer.transform(new DOMSource(document), new StreamResult(writer));
+        return writer.toString();
     }
 
     private class ErrorRecorder implements DOMErrorHandler {